На этот вопрос уже есть ответ здесь:
Я нашел этот ответ как мне... но он просто не работает - он не переименовал ни один файл по неизвестной мне причине
Прежде чем я начал искать вокруг, я думал, что это должно быть легкой задачей даже для начинающего пингвина, но мне так не кажется.
Например, я просто не могу сказать ls
перечислить все *.txt
во всех подпапках, что было для меня неожиданностью (без grep или чего-то подобного).
Затем я нашел find
и find . -name name_1.txt
перечисляют файлы нормально, но
for f in $(find . -name name_1. txt) ; do echo "$f" ; done
разделяет целые пути файлов пробелом как разделителем, поэтому невозможно передать этот вывод в какую-нибудь команду типа mv
или rename
Я хочу спросить, что не так с вышеприведенной командой и, если возможно, какой-нибудь хитрый oneliner, чтобы я мог рекурсивно переименовать name_1. txt
в name_2.txt
find . -name '*.txt' -print0 | xargs -0 -n1 bash -c 'mv "$0" "${0/oldname/newname}"'
Очевидно, это переименовывает шаблон, просто простой пример, но остерегайтесь этого, как это, отредактирует целый путь, не только имя файла.
команда mmv сделает это в довольно простом вызове:
mmv ";name_1.txt" "#1name_2.txt"
""; подстановочный знак, который снова используется в заменяющем имени файла как "#1" соответствия также подкаталоги.
При необходимости в более сложных примерах необходимо изучить страницу справочника.
Вы могли исследовать изобилие доступного выбора:
`$ apt-cache search rename | grep -i rename`
Как @ams указывает, много рекурсивных решений для замены требуют, чтобы Вы работали с целым путем, не только именем файла.
Я использую find
-execdir
действие для решения этой проблемы. Если Вы используете -execdir
вместо -exec
, указанная команда выполняется от подкаталога, содержащего подобранный файл. Так, вместо того, чтобы передать целый путь к rename
, это только передает ./filename
. Это делает намного легче записать команду замены.
find /the/path -type f \
-name '*_one.txt' \
-execdir rename 's/\.\/(.+)_one\.txt$/$1_two.txt/' {} \;
Подробно:
-type f
средства только ищут файлы, не каталоги-name '*_one.txt'
средство означает только имена файлов соответствия тот конец в _one.txtrename
команда вместо mv. переименовывает, использует регулярное выражение Perl для переименования каждого файла.-type
и -name
символ продолжения строки удара. Я использую их для создания этого примера более читаемым, но они не нужны на практике.-execdir
строка требуется. Это там, чтобы выйти из точки с запятой, которая завершает команду, выполненную -execdir
. Забава!Объяснение regex:
s/
запустите regex\.\/
соответствуйте продвижению./это передачи-execdir в. Используйте \для выхода. и / метасимволы(.+)
соответствуйте запуску имени файла. Круглые скобки получают соответствие для более позднего использования_one\.txt
соответствуйте "_one.txt", выйдите из точечного метасимвола$
привяжите соответствие в конце строки/
отмечает конец части "соответствия" regex и запуска части "замены"$1
ссылается на существующее имя файла, потому что мы получили его с круглыми скобками. При использовании нескольких наборов круглых скобок в части "соответствия" можно отослать к ним сюда использование 2$, 3$, и т.д._two.txt
новое имя файла закончится в "_two.txt". Никакая потребность выйти из точечного метасимвола здесь в разделе "замены"/
конец regexПрежде
tree --charset=ascii
|-- a_one.txt
|-- b_one.txt
|-- Not_this.txt
`-- dir1
`-- c_one.txt
После
tree --charset=ascii
|-- a_two.txt
|-- b_two.txt
|-- Not_this.txt
`-- dir1
`-- c_two.txt
Подсказка: rename
опция-n полезна. Это делает пробный прогон и показывает Вам, что называет его, изменится, но не вносит изменений.