Следующее является прямым исправлением вашего подхода:
find . -type f -name 'file*' -exec sh -c 'x="{}"; mv "$x" "${x}_renamed"' \;
Тем не менее, это очень дорого, если у вас много подходящих файлов, потому что вы запускаете новую оболочку (которая выполняет a mv
) для каждого соответствия. И если у вас есть забавные символы в любом имени файла, это взорвется. Более эффективный и безопасный подход заключается в следующем:
find . -type f -name 'file*' -print0 | xargs --null -I{} mv {} {}_renamed
Это также имеет преимущество работы со странно названными файлами. Если find
поддерживает это, это может быть уменьшено до
find . -type f -name 'file*' -exec mv {} {}_renamed \;
xargs
Версия полезна , когда не используется {}
, так как в
find .... -print0 | xargs --null rm
Здесь rm
вызывается один раз (или с большим количеством файлов несколько раз), но не для каждого файла.
Я удалил basename
в вас вопрос, потому что это , вероятно , неправильно: вы бы перейти foo/bar/file8
к file8_renamed
не foo/bar/file8_renamed
.
Редактирует (как предложено в комментариях):
- Добавлено сокращено
find
безxargs
- Добавлена наклейка безопасности
x
это бесполезно:find . -type f -name 'file*' -exec mv {} "{}_renamed" \;
xargs
версия имеет ту же эффективность, что и в первом примере /x
только для того, чтобы напрямую исправить подход аскера.{}
непосредственно вsh -c "…"
команде shell ( ) - вы всегда должны передавать ее в качестве аргумента. (2) Не все версииfind
поддерживают{}_renamed
конструкцию. (3) Я не понимаю вашего утверждения,xargs
которое полезно для удаления файлов (в отличие от их переименования).xargs
неmv
противrm
, но использование{}
против без. Первое похоже наmv file1 file1_renamed; mv file2 file2_renamed
то, в то время как второеrm file1 file2
.Попробовав первый ответ и немного поиграв с ним, я обнаружил, что это можно сделать немного короче и менее сложно, используя
-execdir
:Похоже, он должен делать именно то, что вам нужно.
источник
find
реализациями, которые поддерживают,-execdir
а{}
не в целом, это также самый безопасный. Вы можете добавить-i
кmv
хотя (и-T
если вашmv
поддерживает его)mv
подсказку или в дополнение к ней, вы можете (без сомнения, в зависимости от того,find
поддерживает ли ваша реализация это) и использовать-okdir
команду, которая будет выводить команду, которая будет выполнена перед ее выполнением.-depth
это также хорошая идея, если вы собираетесь также коснуться имен каталогов.-execdir
имеет один очень неприятный недостаток,find
отказывается делать что-либо, еслиPATH
есть какие-либо относительные пути ... askubuntu.com/questions/621132/…find: The relative path XXX is included in the PATH environment
Другой подход заключается в использовании
while read
циклическогоfind
вывода. Это позволяет получить доступ к каждому имени файла в качестве переменного , которой можно манипулировать без необходимости беспокоиться о дополнительных затратах / потенциале вопросах безопасности порождая отдельныйsh -c
процесс , используяfind
«s-exec
варианта.И если используемая оболочка поддерживает
-d
опцию для указанияread
разделителя, вы можете поддерживать файлы со странными именами (например, с новой строкой), используя следующее:источник
Я хочу расширить первый ответ и отметить, что это не будет работать, чтобы добавить к имени файла, так как
./
префикс пути присутствует в аргументе имени файла.Изменяя ответ Томаса Эркера, я считаю, что этот подход более общий
Параметры XARGS:
--null
Указывает, что каждый переданный аргументstdin
заканчивается нулевым символом (\0
). Таким образом, имя файла может содержать пробелы, в противном случае каждое слово будет рассматриваться как отдельный параметр дляmv
команды.-I replace-str
Каждое вхождениеreplace-str
будет заменено аргументом, прочитанным изstdin
. Таким образом, вы можете изменить его на другую строку, если вам это нужно.источник
pringf "%f\0"
вместоprint0
?-print0
будет генерировать./
префиксы, еслиPATTERN
содержит метасимволы оболочки, которые мешают при переименовании чего-то, что префиксирует исходные имена. (например, переименовать0 - foo.txt
в00 - foo.txt
,1 - bar.txt
в01 - bar.txt
и т. д.)Я был в состоянии сделать что - то подобное с
for
,find
иmv
.Это находит все
config.yml
файлы и переименовывает их вconfig.yml.bak
источник
for
и выполнить массовую операцию.