На * nix без rename
perl доступно
В некоторых * 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, используя sed -r
или sed -E
зависимости от вашей платформы.
Смотрите POSIX-совместимый man re_format
для полного описания основных и расширенных шаблонов регулярных выражений.