Подтвердить что ты не робот

Переименовывать файлы и каталоги рекурсивно в ubuntu/bash

Я хочу переименовать все файлы и каталоги, содержащие слово "специальный", "обычный". Он должен поддерживать чувствительность к регистру, поэтому "Special" не станет "регулярным".

Как я могу сделать это в bash рекурсивно?

4b9b3361

Ответ 1

Попробуйте сделать это (требуется bash --version > = 4):

shopt -s globstar
rename -n 's/special/regular/' **

Снимите переключатель -n когда ваши тесты в порядке.

warningСуществуют другие инструменты с таким же именем, которые могут или не могут сделать это, поэтому будьте осторожны.

Если вы запустите следующую команду (GNU)

$ file "$(readlink -f "$(type -p rename)")"

и у вас есть результат, как

.../rename: Perl script, ASCII text executable

и не содержащий:

ELF

тогда это кажется правильным инструментом =)

Если нет, чтобы сделать его стандартным (обычно уже так) в Debian и производным, таким как Ubuntu:

$ sudo update-alternatives --set rename /path/to/rename

(замените /path/to/rename на путь вашей команды perl rename.


Если у вас нет этой команды, найдите менеджер пакетов, чтобы установить его или выполните вручную


Наконец, что не менее важно, этот инструмент был первоначально написан Ларри Уоллом, отцом Perl.

Ответ 2

Решение с использованием find:

Только для переименования файлов:

find /your/target/path/ -type f -exec rename 's/special/regular/' '{}' \;

Только для переименования каталогов:

find /your/target/path/ -type d -execdir rename 's/special/regular/' '{}' \+

Чтобы переименовать оба файла и каталоги:

find /your/target/path/ -execdir rename 's/special/regular/' '{}' \+

Ответ 3

Если вы не против установки другого инструмента, вы можете использовать rnm:

rnm -rs '/special/regular/g' -dp -1 *

Он будет проходить через все каталоги/подкаталоги (из-за -dp -1) и заменять специальные регулярными именами.

Ответ 4

ответ @speakr был ключом для меня.

Если вы используете -execdir для преобразования файлов и каталогов, вы также захотите удалить -type f из показанного примера. Чтобы записать это, используйте:

find /your/target/path/ -execdir rename 's/special/regular/' '{}' \+

Кроме того, рассмотрите добавление флага g (global) в регулярное выражение, если вы хотите заменить все вхождения special на regular в заданное имя файла, а не только на первое вхождение. Например:

find /your/target/path/ -execdir rename 's/special/regular/g' '{}' \+

преобразует special-special.jpg в regular-regular.jpg. Без глобального флага вы получите regular-special.jpg.

FYI: GNU Rename по умолчанию не установлен на Mac OSX. Если вы используете менеджер пакетов Homebrew, brew install rename исправит это.

Ответ 5

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

find /your/target/path/ -type d -execdir rename 's/special/regular/' '{}' \;

Тип записи теперь d для каталога и с помощью -execdir.

Мне не удалось решить, как переименовать файлы и каталоги за один проход.

Кто-то прокомментировал ранее, что, как только он переименовал корневую папку, он больше не сможет пройти через дерево файлов. Существует доступный переключатель -d, который выполняет обход глубины снизу вверх, поэтому корень будет переименован последним, я считаю:

find -d /your/target/path/ -type d -execdir rename 's/special/regular/' '{}' \;

Из manpage (man find):

 -d      Cause find to perform a depth-first traversal, i.e., directories are visited in post-order and all entries in a directory will be
         acted on before the directory itself.  By default, find visits directories in pre-order, i.e., before their contents.  Note, the
         default is not a breadth-first traversal.

Ответ 6

Вот еще один подход, который является более переносимым и не зависит от команды rename (поскольку он может требовать различных параметров в зависимости от дистрибутивов).

Он рекурсивно переименовывает файлы и каталоги:

find . -depth -name "*special*" | \
while IFS= read -r ent; do mv $ent ${ent%special*}regular${ent##*special}; done

Что оно делает

  • используйте параметр find с параметром -depth чтобы изменить порядок результатов, выполнив обход в глубину (т.е. все записи в каталоге отображаются перед самим каталогом).
  • делайте подстановки по шаблону, чтобы модифицировать только последнее вхождение регулярного в пути.

Таким образом, сначала изменяются файлы, а затем каждый родительский каталог.

пример

Даем следующее дерево:

├── aa-special-aa
│   └── bb-special
│       ├── special-cc
│       ├── special-dd
│       └── Special-ee
└── special-00

Он генерирует эти команды mv в определенном порядке:

mv ./aa-special-aa/bb-special/special-cc ./aa-special-aa/bb-special/regular-cc
mv ./aa-special-aa/bb-special/special-dd ./aa-special-aa/bb-special/regular-dd
mv ./aa-special-aa/bb-special ./aa-special-aa/bb-regular
mv ./aa-special-aa ./aa-regular-aa
mv ./special-00 ./regular-00

Чтобы получить следующее дерево:

├── aa-regular-aa
│   └── bb-regular
│       ├── regular-cc
│       ├── regular-dd
│       └── Special-ee
└── regular-00