Możemy założyć, że sed
jest dostępny na dowolnym * nix, ale nie możemy być pewni, że będzie obsługiwał sed -n
generowanie poleceń mv. ( UWAGA:sed
robi to tylko GNU ).
Mimo to, bash builtins i sed, możemy szybko uruchomić funkcję powłoki, aby to zrobić.
sedrename() {
if [ $# -gt 1 ]; then
sed_pattern=$1
shift
for file in $(ls $@); do
mv -v "$file" "$(sed $sed_pattern <<< $file)"
done
else
echo "usage: $0 sed_pattern files..."
fi
}
Stosowanie
sedrename 's|\(.*\)\(-[0-9.]*\.pkg\)|\1\2|' *.pkg
before:
./Xft2-2.1.13.pkg
./jasper-1.900.1.pkg
./xorg-libXrandr-1.2.3.pkg
after:
./Xft2.pkg
./jasper.pkg
./xorg-libXrandr.pkg
Tworzenie folderów docelowych:
Ponieważ mv
nie tworzy automatycznie folderów docelowych, nie możemy używać naszej początkowej wersji sedrename
.
To dość mała zmiana, więc fajnie byłoby uwzględnić tę funkcję:
Będziemy potrzebować funkcji narzędzia abspath
(lub ścieżki bezwzględnej), ponieważ bash nie ma tej wbudowanej .
abspath () { case "$1" in
/*)printf "%s\n" "$1";;
*)printf "%s\n" "$PWD/$1";;
esac; }
Gdy już to zrobimy, możemy wygenerować folder docelowy (i) dla wzorca sed / rename, który zawiera nową strukturę folderów.
Dzięki temu będziemy znać nazwy naszych folderów docelowych. Kiedy zmienimy nazwę, będziemy musieli użyć jej na docelowej nazwie pliku.
# generate the rename target
target="$(sed $sed_pattern <<< $file)"
# Use absolute path of the rename target to make target folder structure
mkdir -p "$(dirname $(abspath $target))"
# finally move the file to the target name/folders
mv -v "$file" "$target"
Oto skrypt obsługujący pełny folder ...
sedrename() {
if [ $# -gt 1 ]; then
sed_pattern=$1
shift
for file in $(ls $@); do
target="$(sed $sed_pattern <<< $file)"
mkdir -p "$(dirname $(abspath $target))"
mv -v "$file" "$target"
done
else
echo "usage: $0 sed_pattern files..."
fi
}
Oczywiście nadal działa, gdy nie mamy również określonych folderów docelowych.
Gdybyśmy chcieli umieścić wszystkie utwory w folderze, ./Beethoven/
możemy to zrobić:
Stosowanie
sedrename 's|Beethoven - |Beethoven/|g' *.mp3
before:
./Beethoven - Fur Elise.mp3
./Beethoven - Moonlight Sonata.mp3
./Beethoven - Ode to Joy.mp3
./Beethoven - Rage Over the Lost Penny.mp3
after:
./Beethoven/Fur Elise.mp3
./Beethoven/Moonlight Sonata.mp3
./Beethoven/Ode to Joy.mp3
./Beethoven/Rage Over the Lost Penny.mp3
Runda bonusowa ...
Użycie tego skryptu do przenoszenia plików z folderów do jednego folderu:
Zakładając, że chcieliśmy zebrać wszystkie pasujące pliki i umieścić je w bieżącym folderze, możemy to zrobić:
sedrename 's|.*/||' **/*.mp3
before:
./Beethoven/Fur Elise.mp3
./Beethoven/Moonlight Sonata.mp3
./Beethoven/Ode to Joy.mp3
./Beethoven/Rage Over the Lost Penny.mp3
after:
./Beethoven/ # (now empty)
./Fur Elise.mp3
./Moonlight Sonata.mp3
./Ode to Joy.mp3
./Rage Over the Lost Penny.mp3
Uwaga na temat wzorców sed regex
W tym skrypcie obowiązują regularne reguły wzorca sed, te wzorce nie są PCRE (wyrażenia regularne zgodne z Perlem). Możesz mieć rozszerzoną składnię wyrażeń regularnych sed, używając jednej z nich sed -r
lub w sed -E
zależności od platformy.
man re_format
Pełny opis podstawowych i rozszerzonych wzorców regexp sed można znaleźć w dokumencie zgodnym z POSIX .