Antworten:
Alle Verzeichnisse auf einer Ebene oder rekursiv?
Auf einer Ebene:
autoload zmv
zmv -o-i -Q 'root/(*)(/)' 'root/${1:l}'
Rekursiv:
zmv -o-i -Q 'root/(**/)(*)(/)' 'root/$1${2:l}'
Erläuterungen: zmvBenennt Dateien, die mit einem Muster übereinstimmen, gemäß dem angegebenen Ersetzungstext um. -o-iÜbergibt die -iOption an jeden mvBefehl unter der Haube (siehe unten). Im Ersetzungstext, $1, $2, usw., sind die aufeinanderfolgenden klammerten Gruppen in dem Muster. **bezeichnet alle (Unter-) * Verzeichnisse rekursiv. Das Finale (/)ist keine in Klammern gesetzte Gruppe, sondern ein Glob-Qualifikationsmerkmal, das bedeutet, dass nur Verzeichnisse abgeglichen werden. ${2:l}konvertiert $2in Kleinbuchstaben.
Auf einer Ebene:
for x in root/*/; do mv -i "$x" "$(printf %s "$x" | tr '[:upper:]' '[:lower:]')"; done
Das Finale /schränkt den Abgleich auf Verzeichnisse ein und mv -ifordert im Falle einer Kollision eine Bestätigung an. Entfernen Sie das -izu überschreibende Element im Falle einer Kollision und verwenden Sie yes n | for …. Keine Aufforderung und keine kollidierende Umbenennung durchführen.
Rekursiv:
find root/* -depth -type d -exec sh -c '
t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
[ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;
Durch die Verwendung von wird -depthsichergestellt, dass tief verschachtelte Verzeichnisse vor ihren Vorfahren verarbeitet werden. Die Namensverarbeitung beruht darauf, dass ein /; Wenn Sie operieren im aktuellen Verzeichnis aufrufen möchten, verwenden Sie ./*(Anpassung des Shell-Skripts zur Bewältigung von .oder *als Übung für den Leser).
Hier verwende ich das Perl-Umbenennungsskript, als das Debian und Ubuntu ausgeliefert werden /usr/bin/prename(normalerweise auch verfügbar rename). Auf einer Ebene:
rename 's!/([^/]*/?)$!\L/$1!' root/*/
Rekursiv mit bash ≥4 oder zsh:
shopt -s globstar # only in bash
rename 's!/([^/]*/?)$!\L/$1!' root/**/*/
Rekursiv portabel:
find root -depth -type d -exec rename -n 's!/([^/]*/?)$!\L/$1!' {} +
-execdirdas ist genial: unix.stackexchange.com/questions/5412/... ich dann festgestellt , dass es etwas hat PATHWahnsinn und war traurig :-(
Es gibt keinen einzigen Befehl, der das erledigt, aber Sie können so etwas tun:
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
Wenn es robust sein soll, sollten Sie berücksichtigen, dass es bereits zwei Verzeichnisse gibt, die sich nur für den Fall unterscheiden.
Als Einzeiler:
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, konnte es aber nicht ganz verstehen
for fd in */;vermeiden, dass überprüft werden muss, ob es sich um ein Verzeichnis handelt, aber ich habe keine Ahnung, ob dieser Instinkt gut ist.
trbereits einen Bereich, tr '[A-Z]' '[a-z]'übersetzt also im Vorbeigehen [nach [und ]nach ]. Das ist nutzlos, aber harmlos; Ohne die Anführungszeichen würde die Shell jedoch die Klammern erweitern, wenn sich im aktuellen Verzeichnis eine Datei mit einem Namen in Großbuchstaben befindet.
Ich habe dies als eine Ein-Linien-Herausforderung angesehen :) Stellen Sie zunächst einen Testfall auf:
$ 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
Ich benutze find, um die Verzeichnisse mit Großbuchstaben zu erkennen und sie dann über in Kleinbuchstaben zu schreiben . Vermutlich ist das Verwenden etwas hackig, aber mein Kopf explodiert immer, wenn ich versuche, den Dingen direkt zu entkommen .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
Seien Sie gewarnt: Diese Lösung prüft nicht, ob Downcasing zu Kollisionen führt!
mv -i. Ein größeres Problem ist, dass Sie nicht die richtigen Anführungszeichen verwendet haben, sodass Ihr Befehl fehlschlägt, wenn \[*?der Name Sonderzeichen (Leerzeichen oder ) enthält. Es hat keinen Sinn, es findsei denn, es ist rekursiv, und dann brauchen Sie find -depthund -pathmüssen es sein -name. Siehe meine Antwort für Arbeitsbeispiele.
mv -inachdem ich das geschrieben habe. Guter Punkt mit dem Zitieren ...
find -execdir| umbenennen
Dies wäre der beste Weg, es zu tun, wenn es nicht den relativen Pfadverrücktheit gäbe, da es Perl-Regex-Fu vermeidet, nur auf den Basisnamen zu reagieren:
PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
find a -depth -execdir rename 's/(.*)/\L$1/' '{}' \;
-execdircds zuerst in das Verzeichnis, bevor es nur mit dem Basisnamen ausgeführt wird.
Leider kann ich diesen PATHHacking-Teil nicht loswerden und find -execdirweigere mich, irgendetwas zu tun, wenn Sie einen relativen Pfad in PATH... haben: /ubuntu/621132/why-using-the-execdir-action- is-insecure-for-directory-which-is-the-path / 1109378 # 1109378
mv -i a aGeben Sie "mv: a umbenennen in a / a: Ungültiges Argument" ein.