Скрипт Bash для рекурсивного переименования папок - PullRequest
4 голосов
/ 09 ноября 2011

Я хочу переименовать все мои папки и папки в этих папках, чтобы все подчеркивания в имени папки заменялись пробелами. Вы можете помочь мне с этим?

Ответы [ 3 ]

7 голосов
/ 09 ноября 2011

Ответ, использующий -execdir, проще, но будет работать только с версиями find, которые поддерживают -execdir, такими как GNU find, поскольку POSIX указывает только -exec.

Если вы просто хотите использовать bash, это удивительно сложно сделать правильно, так как вы переименовываете каталоги, которые просматривает find. Даже если вы правильно выполнили порядок, используя опцию -depth для find, вам необходимо убедиться, что вы переписываете только последний компонент пути с каждым -exec. Ниже приведен тривиальный вариант одного из примеров, приведенных в FAQ по Bash , и, похоже, он мне подходит:

find . -depth -name "*_*" -exec bash -c 'dir=${1%/*} base=${1##*/}; mv "$1" "$dir/${base//_/ }"' _ {} \;

В этом ответе на часто задаваемые вопросы обсуждается проблема рекурсивного именования папок, которая может представлять интерес.


Обновление : Поскольку этот однострочный текст довольно сложен, возможно, стоит немного разбить его в интересах объяснения. По сути, команда find:

find . -depth -name "*_*" -exec bash -c [SOME-STUFF] _ {} \;

Другими словами, найдите все каталоги, которые содержат подчеркивание, и для каждого такого каталога, начиная с самого глубокого, запустите скрипт bash [SOME-STUFF], с параметром 0 как _ (чтобы указать, что мы не делаем позаботьтесь об этом) и параметр 1 в качестве имени найденного найденного файла. (find заменит имя файла на {} после -exec. \; просто завершает команду, которую запускает -exec.)

Тогда часть [SOME-STUFF] состоит из:

dir=${1%/*}

... который, используя расширение параметра , удалит самое короткое совпадение для /* с конца $1 (имя файла) и установит dir в качестве результата. Точно так же эта часть:

base=${1##*/}

... удаляет самое длинное совпадение */ с начала $1 и устанавливает base в результат. Так что base - это только последний компонент пути.

Тогда переименование фактически выполняется командой mv, которая:

mv "$1" "$dir/${base//_/ }"

Здесь снова используется расширение параметров, на этот раз с синтаксисом ${parameter/pattern/string}. Имя файла ($1) переименовывается в $dir, за которым следует $base, но каждое подчеркивание в $base заменяется пробелом.

1 голос
/ 09 ноября 2011

Да, просто cd to / dir и:

find -depth -type d -execdir rename 's/_/ /g' {} \;

В зависимости от дистрибутива, вам нужно переименовать perl (иногда prename).

Если

file $(type -p rename)

вывод содержит ELF, что выглядит плохо;)

1012 * редактировать * -depth и -execdir добавлены

0 голосов
/ 09 ноября 2011

Если у вас есть bash4, вы можете запустить:

for i in **; do [[ -d "$i" ]] || continue; mv "$i" "${i/_/ }"; done
...