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: zmv
rinomina i file corrispondenti a un modello in base al testo di sostituzione fornito. -o-i
passa l' -i
opzione a ciascun mv
comando 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 $2
in 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 -i
fa chiedere conferma in caso di collisione. Rimuovere -i
per 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 -depth
assicura 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/prename
fornito da Debian e Ubuntu (normalmente disponibile rename
anche). 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!' {} +
-execdir
che è fantastico: unix.stackexchange.com/questions/5412/… Ho poi scoperto che ha un po 'di PATH
follia 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.
tr
aspetta 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 find
per 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 -c
find
$ (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 find
meno che non si ripeta, quindi è necessario find -depth
e -path
deve esserlo -name
. Vedi la mia risposta per esempi funzionanti.
mv -i
dopo 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/' '{}' \;
-execdir
prima cd
s nella directory prima di eseguire solo sul basename.
Sfortunatamente, non riesco a liberarmi di quella PATH
parte di hacking, mi find -execdir
rifiuto 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 a
dare "mv: rinomina a a / a: argomento non valido".