Я хочу переименовать все файлы и каталоги, содержащие слово "специальный", "обычный". Он должен поддерживать чувствительность к регистру, поэтому "Special" не станет "регулярным".
Как я могу сделать это в bash рекурсивно?
Я хочу переименовать все файлы и каталоги, содержащие слово "специальный", "обычный". Он должен поддерживать чувствительность к регистру, поэтому "Special" не станет "регулярным".
Как я могу сделать это в bash рекурсивно?
Попробуйте сделать это (требуется bash --version
> = 4):
shopt -s globstar
rename -n 's/special/regular/' **
Снимите переключатель -n
когда ваши тесты в порядке.
Существуют другие инструменты с таким же именем, которые могут или не могут сделать это, поэтому будьте осторожны.
Если вы запустите следующую команду (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.
Решение с использованием 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/' '{}' \+
Если вы не против установки другого инструмента, вы можете использовать rnm:
rnm -rs '/special/regular/g' -dp -1 *
Он будет проходить через все каталоги/подкаталоги (из-за -dp -1
) и заменять специальные регулярными именами.
ответ @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
исправит это.
Для тех, кто просто хочет переименовать каталоги, вы можете использовать эту команду:
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.
Вот еще один подход, который является более переносимым и не зависит от команды rename
(поскольку он может требовать различных параметров в зависимости от дистрибутивов).
Он рекурсивно переименовывает файлы и каталоги:
find . -depth -name "*special*" | \
while IFS= read -r ent; do mv $ent ${ent%special*}regular${ent##*special}; done
Что оно делает
-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