20

Как мне рекурсивно переименовать все файлы в каталоге, меняя одно расширение на другое, для тысяч файлов в тысячах подпапок? Я вижу много команд, которые делают почти то, что я хочу, но не совсем.

find . -name "*.andnav" -exec rename .andnav .tile {} \;
syntax error at (eval 1) line 1, near "."

...

rename -nv 's/\.andnav$/\.tile/i' *.andnav
0.png.andnav renamed as 0.png.tile

5 ответов5

20

Догадаться

find . -name "*.andnav" -exec rename -v 's/\.andnav$/\.tile/i' {} \;
./0/0.png.andnav renamed as ./0/0.png.tile
./0/1.png.andnav renamed as ./0/1.png.tile
./1/0.png.andnav renamed as ./1/0.png.tile
./1/1.png.andnav renamed as ./1/1.png.tile

конечно удалите -v, когда будете это делать, иначе вы потеряете время на отображение всех файлов

13

С зш:

autoload zmv
zmv -n '(**/)(*).andnav' '$1$2.tile'

Удалите -n чтобы фактически выполнить переименование.

13

Что-то вроде:

find . -name '*.andnav' -exec sh -c 'mv "$0" "${0%.andnav}.tile"' {} \;
4

Я обнаружил, что этот метод легче и легче читать:

find . -name "*.andnav" | rename "s/\.andnav$/.tile/"

По крайней мере, в деривациях Ubuntu переименование берет список файлов из STDIN, если их нет в командной строке. И это можно легко проверить с помощью:

find . -name "*.andnav" | rename -vn "s/\.andnav$/.tile/"

пока не поймешь правильно.

0

Переименовывайте файлы и каталоги с помощью find -execdir | rename

Если вы собираетесь переименовывать как файлы, так и каталоги не просто с помощью суффикса, тогда это хороший шаблон:

PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
  find . -depth -execdir rename 's/findme/replaceme/' '{}' \;

Параметр awesome -execdir делает cd в каталог перед выполнением команды rename , в отличие от -exec .

-depth убедитесь, что переименование происходит сначала для детей, а затем для родителей, чтобы предотвратить потенциальные проблемы с отсутствующими родительскими каталогами.

-execdir требуется, потому что переименование плохо работает с путями ввода неосновного имени, например, следующие ошибки:

rename 's/findme/replaceme/g' acc/acc

Взлом PATH необходим, потому что -execdir имеет один очень раздражающий недостаток: find чрезвычайно самоуверен и отказывается что-либо делать с -execdir если у вас есть относительные пути в переменной окружения PATH , например, ./node_modules/.bin , в случае сбоя:

find: Относительный путь «./node_modules/.bin» включен в переменную среды PATH, которая небезопасна в сочетании с действием -execdir команды find. Пожалуйста, удалите эту запись из $ PATH

Смотрите также: https://askubuntu.com/questions/621132/why-using-the-execdir-action-is-insecure-for-directory-which-is-in-the-path/1109378#1109378

-execdir является расширением GNU find для POSIX. rename основано на Perl и происходит из пакета rename . Проверено в Ubuntu 18.10.

Переименовать обходное решение

Если ваши входные пути не получены из find , или если вам надоело относительное раздражение пути, мы можем использовать некоторые возможности Perl для безопасного переименования каталогов, как в:

git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'

Я не нашел удобного аналога для -execdir с xargs: xargs: перед выполнением изменить рабочий каталог на путь к файлу?

sort -r необходима для того, чтобы файлы следовали за соответствующими каталогами, поскольку более длинные пути идут после более коротких с тем же префиксом.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .