Respostas:
Todos os diretórios em um nível ou recursivamente?
Em um nível:
autoload zmv
zmv -o-i -Q 'root/(*)(/)' 'root/${1:l}'
Recursivamente:
zmv -o-i -Q 'root/(**/)(*)(/)' 'root/$1${2:l}'
Explicações: zmvrenomeia os arquivos que correspondem a um padrão de acordo com o texto de substituição fornecido. -o-ipassa a -iopção para cada mvcomando sob o capô (veja abaixo). No texto de substituição, $1, $2, etc, são os grupos entre parênteses sucessivas no padrão. **significa todos os (sub) * diretórios, recursivamente. A final (/)não é um grupo entre parênteses, mas um qualificador global que significa corresponder apenas aos diretórios. ${2:l}converte $2para minúsculas.
Em um nível:
for x in root/*/; do mv -i "$x" "$(printf %s "$x" | tr '[:upper:]' '[:lower:]')"; done
O final /restringe a correspondência aos diretórios e mv -isolicita a confirmação em caso de colisão. Remova o -ipara substituir em caso de colisão e use yes n | for …. para não ser solicitado e não executar nenhuma renomeação que colidiria.
Recursivamente:
find root/* -depth -type d -exec sh -c '
t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
[ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;
O uso de -depthgarante que os diretórios profundamente aninhados sejam processados antes de seus ancestrais. O processamento de nomes depende da existência de um /; se você quiser chamar de operar no diretório atual, use ./*(adaptar o shell script para lidar com .ou *é deixado como um exercício para o leitor).
Aqui eu uso o script de renomeação do Perl que o Debian e o Ubuntu lançam como /usr/bin/prename(normalmente também disponíveis rename). Em um nível:
rename 's!/([^/]*/?)$!\L/$1!' root/*/
Recursivamente, com bash ≥4 ou zsh:
shopt -s globstar # only in bash
rename 's!/([^/]*/?)$!\L/$1!' root/**/*/
Recursivamente, portably:
find root -depth -type d -exec rename -n 's!/([^/]*/?)$!\L/$1!' {} +
-execdirque é incrível: unix.stackexchange.com/questions/5412/… Descobri que ele tinha uma PATHloucura e ficou triste :-(
Não há um único comando que faça isso, mas você pode fazer algo assim:
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
Se você precisar que ele seja robusto, considere quando já existem dois diretórios que diferem apenas no caso.
Como uma linha:
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, mas não consegui entender
for fd in */;, evitando assim a necessidade de verificar se era um diretório, mas não tenho idéia se esse instinto era bom.
trjá espera um intervalo, então tr '[A-Z]' '[a-z]'traduz [para [e ]para ]de passagem. Isso é inútil, mas inofensivo; no entanto, sem as aspas, o shell expandiria os colchetes se houvesse um arquivo com o nome de uma letra maiúscula no diretório atual.
Tomei isso como um desafio de uma linha :) Primeiro, estabeleça um caso de teste:
$ 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
Eu uso findpara localizar os diretórios com letras maiúsculas e depois colocá-los em minúsculas . Acho que usar é um pouco hack-ish, mas minha cabeça sempre explode quando tento escapar das coisas diretamente.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
Esteja avisado: Esta solução não verifica se o downcasing causa colisões!
mv -i. Um problema maior é que você não usou a citação adequada; portanto, seu comando falhará se houver caracteres especiais (espaço em branco ou \[*?) em qualquer lugar do nome. Não há nenhum ponto de usar, a findmenos que seja recorrente, e então você precisa find -depthe -pathdeve ser -name. Veja minha resposta para exemplos de trabalho.
mv -idepois de escrever isso. Bom ponto com a citação ...
find -execdir| renomear
Essa seria a melhor maneira de fazer isso, se não fosse a loucura relativa do caminho, pois evita que o Regex fu do Perl atue apenas no nome da base:
PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
find a -depth -execdir rename 's/(.*)/\L$1/' '{}' \;
-execdirprimeiro cds no diretório antes de executar apenas no nome da base.
Infelizmente, não consigo me livrar dessa PATHparte de hackers, find -execdirse recusa a fazer qualquer coisa se você tiver um caminho relativo em PATH...: /ubuntu/621132/why-using-the-execdir-action- é inseguro para o diretório que está no caminho / 1109378 # 1109378
mv -i a adê "mv: renomeie a para a / a: argumento inválido".