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: zmv
Benennt Dateien, die mit einem Muster übereinstimmen, gemäß dem angegebenen Ersetzungstext um. -o-i
Übergibt die -i
Option an jeden mv
Befehl 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 $2
in 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 -i
fordert im Falle einer Kollision eine Bestätigung an. Entfernen Sie das -i
zu ü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 -depth
sichergestellt, 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!' {} +
-execdir
das ist genial: unix.stackexchange.com/questions/5412/... ich dann festgestellt , dass es etwas hat PATH
Wahnsinn 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.
tr
bereits 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 -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
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 find
sei denn, es ist rekursiv, und dann brauchen Sie find -depth
und -path
müssen es sein -name
. Siehe meine Antwort für Arbeitsbeispiele.
mv -i
nachdem 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/' '{}' \;
-execdir
cd
s zuerst in das Verzeichnis, bevor es nur mit dem Basisnamen ausgeführt wird.
Leider kann ich diesen PATH
Hacking-Teil nicht loswerden und find -execdir
weigere 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 a
Geben Sie "mv: a umbenennen in a / a: Ungültiges Argument" ein.