Risposte:
Tutte le directory a un livello o ricorsivamente?
A un livello:
autoload zmv
zmv -o-i -Q 'root/(*)(/)' 'root/${1:l}'
ricorsivamente:
zmv -o-i -Q 'root/(**/)(*)(/)' 'root/$1${2:l}'
Spiegazioni: zmvrinomina i file corrispondenti a un modello in base al testo di sostituzione fornito. -o-ipassa l' -iopzione a ciascun mvcomando sotto il cofano (vedi sotto). Nel testo di sostituzione, $1, $2, ecc, sono i successivi gruppi tra parentesi nel modello. **indica tutte le (sotto) * directory, ricorsivamente. Il finale (/)non è un gruppo tra parentesi ma un qualificatore glob che intende abbinare solo le directory. ${2:l}converte $2in minuscolo.
A un livello:
for x in root/*/; do mv -i "$x" "$(printf %s "$x" | tr '[:upper:]' '[:lower:]')"; done
Il finale /limita la corrispondenza con le directory e lo mv -ifa chiedere conferma in caso di collisione. Rimuovere -iper sovrascrivere in caso di collisione e utilizzare yes n | for …. non essere richiesto e non eseguire alcuna ridenominazione che potrebbe scontrarsi.
ricorsivamente:
find root/* -depth -type d -exec sh -c '
t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
[ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;
L'uso di -depthassicura che le directory profondamente annidate vengano elaborate prima dei loro antenati. L'elaborazione del nome si basa sull'esistenza di un /; se vuoi chiamare operi nella directory corrente, usa ./*(adattando lo script della shell per far fronte .o *viene lasciato come esercizio per il lettore).
Qui uso lo script di rinomina Perl /usr/bin/prenamefornito da Debian e Ubuntu (normalmente disponibile renameanche). A un livello:
rename 's!/([^/]*/?)$!\L/$1!' root/*/
Ricorsivamente, con bash ≥4 o zsh:
shopt -s globstar # only in bash
rename 's!/([^/]*/?)$!\L/$1!' root/**/*/
Ricorsivamente, portabilmente:
find root -depth -type d -exec rename -n 's!/([^/]*/?)$!\L/$1!' {} +
-execdirche è fantastico: unix.stackexchange.com/questions/5412/… Ho poi scoperto che ha un po 'di PATHfollia ed è stato triste :-(
Non esiste un singolo comando che lo farà, ma puoi fare qualcosa del genere:
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 è necessario che sia robusto, è necessario tenere conto di quando esistono già due directory che differiscono solo nel caso.
Come una linea:
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, ma non ci sono riuscito
for fd in */;, evitando così la necessità di verificare se fosse una directory, ma non ho idea se questo istinto fosse buono.
traspetta già un intervallo, quindi si tr '[A-Z]' '[a-z]'traduce [da [e ]verso ]di passaggio. Questo è inutile ma innocuo; tuttavia senza le virgolette la shell espanderebbe le parentesi se ci fosse un file con un nome di una lettera maiuscola nella directory corrente.
Ho preso questo come una sfida di un liner :) In primo luogo, stabilire un caso di prova:
$ 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
Uso findper individuare le directory con le lettere maiuscole e poi le ho minuscole . Immagino che usare sia un po 'hack-ish, ma la mia testa esplode sempre quando provo a sfuggire alle cose per direttamente.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
Attenzione: questa soluzione non controlla se il downcasing porta a collisioni!
mv -i. Un problema più grande è che non hai usato la quotazione corretta, quindi il tuo comando fallirà se ci sono caratteri speciali (spazi bianchi o \[*?) in qualsiasi parte del nome. Non ha senso utilizzare a findmeno che non si ripeta, quindi è necessario find -depthe -pathdeve esserlo -name. Vedi la mia risposta per esempi funzionanti.
mv -idopo aver scritto questo. Buon punto con la citazione ...
find -execdir| rinominare
Questo sarebbe il modo migliore per farlo se non fosse per la follia del percorso relativo, poiché evita che Perl regex fu agisca solo sul nome di base:
PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
find a -depth -execdir rename 's/(.*)/\L$1/' '{}' \;
-execdirprima cds nella directory prima di eseguire solo sul basename.
Sfortunatamente, non riesco a liberarmi di quella PATHparte di hacking, mi find -execdirrifiuto di fare qualsiasi cosa se hai un percorso relativo in PATH...: /ubuntu/621132/why-using-the-execdir-action- è-insicuro-per-directory-che-è-in-the-path / 1.109.378 1.109.378 #
mv -i a adare "mv: rinomina a a / a: argomento non valido".