Ответы:
Все каталоги на одном уровне или рекурсивно?
На одном уровне:
autoload zmv
zmv -o-i -Q 'root/(*)(/)' 'root/${1:l}'
Рекурсивный:
zmv -o-i -Q 'root/(**/)(*)(/)' 'root/$1${2:l}'
Пояснения: zmvпереименовывает файлы, соответствующие шаблону, в соответствии с заданным текстом замены. -o-iпередает -iопцию каждой mvкоманде под капотом (см. ниже). В тексте замены $1, $2и т. Д., Есть последовательные заключенные в скобки группы в шаблоне. **означает все (под) * каталоги, рекурсивно. Финал (/)- это не группа в скобках, а квалификатор glob, означающий совпадение только с каталогами. ${2:l}преобразует $2в нижний регистр
На одном уровне:
for x in root/*/; do mv -i "$x" "$(printf %s "$x" | tr '[:upper:]' '[:lower:]')"; done
Финал /ограничивает соответствие каталогами и mv -iзаставляет запрашивать подтверждение в случае коллизии. Удалите, -iчтобы перезаписать в случае столкновения, и используйте yes n | for …. не получать подсказки и не выполнять переименование, которое может столкнуться.
Рекурсивный:
find root/* -depth -type d -exec sh -c '
t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
[ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;
Использование -depthгарантирует, что глубоко вложенные каталоги обрабатываются перед их предками. Обработка имени зависит от наличия /; если вы хотите вызывать операцию в текущем каталоге, используйте ./*(адаптация сценария оболочки, чтобы справиться .или *оставлена как упражнение для читателя).
Здесь я использую сценарий переименования Perl, который поставляется вместе с Debian и Ubuntu /usr/bin/prename(как правило, также доступен rename). На одном уровне:
rename 's!/([^/]*/?)$!\L/$1!' root/*/
Рекурсивно, с bash ≥4 или zsh:
shopt -s globstar # only in bash
rename 's!/([^/]*/?)$!\L/$1!' root/**/*/
Рекурсивно, переносимо:
find root -depth -type d -exec rename -n 's!/([^/]*/?)$!\L/$1!' {} +
-execdirчто удивительно: unix.stackexchange.com/questions/5412/… Затем я обнаружил, что в нем есть какое-то PATHбезумие и он грустит :-(
Нет ни одной команды, которая это сделает, но вы можете сделать что-то вроде этого:
for fd in */; do
#get lower case version
fd_lower=$(printf %s "$fd" | tr A-Z a-z)
#if it wasn't already lowercase, move it.
[ "$fd" != "$fd_lower" ] && mv "$fd" "$fd_lower"
done
Если вам нужно, чтобы он был надежным, вы должны учитывать, когда уже есть две директории, которые отличаются только регистром.
Как однострочник:
for fd in */; do fd_lower=$(printf %s "$fd" | tr A-Z a-z) && [ "$fd" != "$fd_lower" ] && mv "$fd" "$fd_lower"; done
for file in * ; do if [ -d "$file" ] ; then dest="$(echo $file | sed y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/)" ; [ "$dest" != "$file" ] && mv "$file" "$dest" ; fi ; done
find -type d, но не смог понять
for fd in */;таким, чтобы избежать необходимости проверки, если это был каталог, но я понятия не имею, был ли этот инстинкт хорошим.
trуже ожидает диапазон, так tr '[A-Z]' '[a-z]'переводится [с [и ]в ]мимоходом. Это бесполезно, но безвредно; однако без кавычек оболочка расширит скобки, если в текущем каталоге будет файл с именем, состоящим из одной заглавной буквы.
Я воспринял это как однострочную задачу :) Сначала создайте контрольный пример:
$ for d in foo Bar eVe; do mkdir -p dcthis/$d; touch dcthis/a${d}.txt; done
$ ls dcthis/
Bar aBar.txt aeVe.txt afoo.txt eVe foo
Я использую findдля обозначения каталогов заглавными буквами, а затем с помощью нижнего регистра . Думаю, использование немного хакерство, но моя голова всегда взрывается, когда я пытаюсь избежать чего-то напрямую.sh -c 'mv {} echo {} | tr [:upper:] [:lower:]'sh -cfind
$ (cd dcthis && find . -maxdepth 1 -type d -path '*[A-Z]*' -exec sh -c 'mv {} `echo {} | tr [:upper:] [:lower:]`' \;)
$ ls dcthis/
aBar.txt aeVe.txt afoo.txt bar eve foo
Имейте в виду: это решение не проверяет, приводит ли уменьшение размеров к столкновениям!
mv -i. Большая проблема в том, что вы не использовали правильные кавычки, поэтому ваша команда не будет выполнена, если в имени есть специальные символы (пробел или \[*?). Там нет смысла использовать, findесли только повторения, а затем вам нужно find -depth, и -pathдолжно быть -name. Смотрите мой ответ для рабочих примеров.
mv -iпосле написания этого. Хороший вопрос с цитатой ...
find -execdir| переименование
Это был бы лучший способ сделать это, если бы не безумие относительного пути, так как Perl regex fu не действует только на базовое имя:
PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
find a -depth -execdir rename 's/(.*)/\L$1/' '{}' \;
-execdirсначала cdв каталог, прежде чем выполнять только по базовому имени.
К сожалению, я не могу избавиться от этой PATHхакерской части, find -execdirотказывается что-либо делать, если у вас есть относительный путь в PATH...: /ubuntu/621132/why-using-the-execdir-action- является нестабильным-для-каталог-который-является-в-пути / 1109378 # 1109378
mv -i a aукажите «mv: переименуйте a в / a: неверный аргумент».