Ответ, использующий -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
заменяется пробелом.