107 lines
2.4 KiB
Bash
Executable File
107 lines
2.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Användning:
|
|
mvi KÄLLA MÅL
|
|
mvi KÄLLA1 KÄLLA2 ... KATALOG
|
|
|
|
Flyttar som 'mv', men om en målfil redan finns så läggs ett index in
|
|
före filändelsen, t.ex. "fil.txt" -> "fil.1.txt", "fil.2.txt", ...
|
|
|
|
Exempel:
|
|
mvi bild.jpg bilder/ # bilder/bild.jpg eller bilder/bild.1.jpg
|
|
mvi .env prod/ # prod/.env eller prod/.env.1
|
|
mvi projekt/ arkiv/ # arkiv/projekt eller arkiv/projekt.1
|
|
EOF
|
|
}
|
|
|
|
# Ta reda på om sista argumentet är en katalog (målet när flera källor)
|
|
is_dir() {
|
|
local p=$1
|
|
[[ -d "$p" ]]
|
|
}
|
|
|
|
# Skapa ett indexerat fil-/katalognamn om target redan finns.
|
|
# Regler:
|
|
# - index (".N") injiceras före sista filändelsen
|
|
# - för dolda filer utan ändelse (t.ex. ".env"): ".env.1"
|
|
# - för flera punkter (t.ex. "fil.tar.gz"): "fil.tar.1.gz"
|
|
indexed_path() {
|
|
local target="$1"
|
|
local dir base name ext n candidate
|
|
|
|
dir=$(dirname -- "$target")
|
|
name=$(basename -- "$target")
|
|
|
|
# Dela upp name i bas + ev. ext (sista punkten räknas som extension-separator)
|
|
if [[ "$name" = .* && "$name" != *.* ]]; then
|
|
# Dold fil utan extension (".env")
|
|
base="$name"
|
|
ext=""
|
|
elif [[ "$name" = *.* ]]; then
|
|
base="${name%.*}"
|
|
ext=".${name##*.}"
|
|
else
|
|
base="$name"
|
|
ext=""
|
|
fi
|
|
|
|
n=1
|
|
while :; do
|
|
candidate="${dir}/${base}.${n}${ext}"
|
|
[[ ! -e "$candidate" ]] && { printf '%s\n' "$candidate"; return 0; }
|
|
n=$((n+1))
|
|
done
|
|
}
|
|
|
|
# Flytta en enskild källa till ett givet mål (fil eller katalog)
|
|
move_one() {
|
|
local src="$1"
|
|
local dst="$2"
|
|
local target
|
|
|
|
if [[ -d "$dst" ]]; then
|
|
target="${dst%/}/$(basename -- "$src")"
|
|
else
|
|
target="$dst"
|
|
fi
|
|
|
|
if [[ -e "$target" ]]; then
|
|
target=$(indexed_path "$target")
|
|
fi
|
|
|
|
# Skapa målkatalog om den inte finns (som mv gör med -t dir om den finns)
|
|
mkdir -p -- "$(dirname -- "$target")"
|
|
|
|
mv -- "$src" "$target"
|
|
}
|
|
|
|
# --- Huvudprogram ---
|
|
if [[ $# -lt 2 ]]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
# Sista arg är destination
|
|
dest="${@: -1}"
|
|
sources=("${@:1:$(($#-1))}")
|
|
|
|
# Om flera källor: dest måste vara katalog
|
|
if [[ ${#sources[@]} -gt 1 ]]; then
|
|
if ! is_dir "$dest"; then
|
|
echo "Fel: Flera källor kräver att destinationen är en katalog." >&2
|
|
exit 2
|
|
fi
|
|
fi
|
|
|
|
# Iterera över alla källor
|
|
for src in "${sources[@]}"; do
|
|
if [[ ! -e "$src" ]]; then
|
|
echo "Varning: källan finns inte: $src" >&2
|
|
continue
|
|
fi
|
|
move_one "$src" "$dest"
|
|
done
|