Я хочу переименовать все файлы и каталоги, содержащие слово "специальный", "обычный". Он должен поддерживать чувствительность к регистру, поэтому "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.
shopt -s globstar
?
**
(обозначает рекурсивную), возможно, уже включена.
Решение с использованием 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
исправит это.
/special/regular/regular-specilal.jpeg
Вот еще один подход, который является более переносимым и не зависит от команды 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
Для тех, кто просто хочет переименовать каталоги, вы можете использовать эту команду:
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.