Простой способ получить скрипт slhck для рекурсивного поиска в подпапках и файлах, если вы используете bash, - это добавить shopt -s globstar
а затем изменить *
на **
.
Это не будет работать правильно, если у вас есть каталоги с «нелегальными» символами в их именах.
Вы можете обойти это, просто запустив скрипт n+1 раз, где n - максимальное количество каталогов с недопустимыми символами в любом пути.
Например, если у вас есть каталог f@cat
каталогом dog#
и fox!
каталог ниже, вам нужно будет запустить скрипт четыре раза.
Я даю лучший способ сделать это ниже.
- Сценарий slhck действительно должен сказать
mv -i
вместо mv
. Если у вас есть файлы с именами, скажем, cost+tax
и cost-tax
, скрипт переименует их оба в costtax
(или cost_tax
, после того как мы внесем это изменение).
Это закроет первый файл вторым файлом.
Опция -i
(i nteractive) заставит mv
запросить подтверждение.
Вам придется обрабатывать такие столкновения, как это вручную.
- Чтобы заменить «недопустимые» символы подчеркиванием, замените
${file//[^0-9A-Za-z.]}
${file//[^0-9A-Za-z.]/_}
(или, что еще лучше, ${file//[^0-9A-Za-z._]/_}
).
Таким образом, с учетом вышеуказанных изменений, сценарий slhck становится
shopt -s globstar
for f in "$1"/**
do
dir="$(dirname "$f")"
file="$(basename "$f")"
mv -i -- "$f" "${dir}/${file//[^0-9A-Za-z._]/_}"
done
При выполнении этого, быть абсолютно уверены, что указать аргумент (например,).; в противном случае он попытается переименовать все файлы в файловой системе (начиная с .
).
Вы, вероятно, должны поместить что-то в скрипт, чтобы убедиться, что аргумент /
не равен нулю.
Это имеет проблемы с каталогами с недопустимыми символами в их именах, потому что **
расширяется до списка всех файлов и каталогов в поддереве ниже $1
с ветвями в порядке сверху вниз.
Итак, если у вас есть f@cat/dog#
, он увидит f@cat
и f@cat/dog#
качестве аргументов.
Поэтому он будет переименовывать f@cat
в f_cat
, а затем искать f@cat/dog#
- который больше не существует, потому что он был переименован в f_cat/dog#
.
Мы можем исправить это, сделав
find "$1" -depth -name '*[^0-9A-Za-z._]*' -exec sh -c \
'for f do dir="$(dirname "$f")"; file="$(basename "$f")";
mv -i -- "$f" "${dir}/${file//[^0-9A-Za-z.]/_}"; done' sh {} +
Опция -depth
для find
заставляет его смотреть на ветви каталогов в порядке снизу вверх.
Директива -name
заставляет смотреть только имена файлов, которые нужно переименовать.
(Другой скрипт выдаст сообщения об ошибках, когда попытается переименовать файлы для себя, потому что в их именах нет недопустимых символов.)
Затем find
передает имена в оболочку, которая выполняет те же действия, что и скрипт, но одной командой.