На * NIX без Perl rename
доступны
В некоторых * nix переименование недоступно, поэтому необходимо выполнить переименование другим способом. Несколько лет назад я предложил zmv
здесь, что, хотя и здорово, но не обязательно доступно.
Используя встроенные функции и sed, мы можем быстро создать сценарий оболочки, чтобы сделать это, что дает нам синтаксис, очень похожий на сценарий perl-переименования, и, хотя ему не хватает изощренности в обработке ошибок, он выполняет свою работу.
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
}
использование
sedrename 's/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:
./Fur Elise.mp3
./Moonlight Sonata.mp3
./Ode to Joy.mp3
./Rage Over the Lost Penny.mp3
Скажем, мы тоже хотели создать целевые папки ...
Поскольку mv
папки не создаются, мы не можем их использовать, sedrename
как здесь, но это довольно небольшое изменение, поэтому я думаю, что было бы неплохо включить их тоже.
Нам нужна служебная функция abspath
(или абсолютный путь), чтобы мы могли сгенерировать целевую папку (и) для шаблона sed / rename, который включает новую структуру папок.
abspath () { case "$1" in
/*)printf "%s\n" "$1";;
*)printf "%s\n" "$PWD/$1";;
esac; }
Это гарантирует, что мы знаем имена наших целевых папок. Когда мы переименуем, нам нужно будет использовать его в имени целевого файла.
# 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"
Вот полный сценарий с поддержкой папок ...
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
}
Конечно, это все еще работает, когда у нас нет определенных целевых папок.
Если мы хотим поместить все песни в папку, ./Beethoven/
мы можем сделать это:
использование
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
Бонус раунд ...
Используя этот скрипт для перемещения файлов из папок в одну папку:
Предполагая, что мы хотим собрать все соответствующие файлы и поместить их в текущую папку, мы можем сделать это:
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
Обратите внимание на шаблоны регулярных выражений
В этом сценарии применяются правила регулярных шаблонов sed, эти шаблоны не являются PCRE (регулярные выражения, совместимые с Perl). Вы могли бы использовать расширенный синтаксис регулярных выражений, используя один sed -r
или в sed -E
зависимости от вашей платформы.
См. POSIX-совместимое man re_format
для полного описания основных и расширенных шаблонов регулярных выражений.