Рекурсивное переименование файлов и каталогов в Ubuntu / Bash

49

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

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

Теги:
find

6 ответов

65
Лучший ответ

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

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

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

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

Если вы запустите следующую команду (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.

  • 5
    Для чего shopt -s globstar ?
  • 3
    Он включает функцию bash ** (обозначает рекурсивную), возможно, уже включена.
Показать ещё 18 комментариев
80

Решение с использованием 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/' '{}' \+
  • 0
    спот на спикере, спасибо
  • 1
    @speakr, отличное решение, спасибо! Не могли бы вы предоставить более подробную информацию о том, что он делает, особенно эту часть "{}"? Быстрое изумление не помогло, поэтому я подумал, что эта информация может быть полезна и для других.
Показать ещё 6 комментариев
4

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

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

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

  • 0
    Это установлено с Homebrew?
  • 0
    @LokMac: Я не думаю, что он доступен в homebrew (я только упаковываю двоичные файлы для ОС на основе Debian). Если у вас есть automake, вы можете установить его в любой системе Unix (инструкции находятся в файле readme ).
Показать ещё 1 комментарий
2

ответ @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 исправит это.

  • 0
    будет ли это исправление обрабатывать включая папки? например /special/regular/regular-specilal.jpeg
0

Вот еще один подход, который является более переносимым и не зависит от команды 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
0

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

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.
  • 0
    Если кто-то может уточнить, что делается для действия команды для файлов и каталогов за один проход, это также будет полезно, и я обновлю этот ответ с помощью команды.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню