Простой способ получить скрипт 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 передает имена в оболочку, которая выполняет те же действия, что и скрипт, но одной командой.