Senkung aller Verzeichnisse unter einem Verzeichnis

12

Ich möchte den Namen jedes Verzeichnisses unter einem Verzeichnis in Kleinbuchstaben schreiben. Mit welchen Befehlen kann ich das machen?

erkangur
quelle

Antworten:

10

Alle Verzeichnisse auf einer Ebene oder rekursiv?

Zsh

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.

tragbar

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).

Perl umbenennen

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!' {} +
Gilles 'SO - hör auf böse zu sein'
quelle
Zumindest unter OS X schlägt dies fehl, wenn Verzeichnisse bereits in Kleinbuchstaben vorliegen: mv -i a aGeben Sie "mv: a umbenennen in a / a: Ungültiges Argument" ein.
Janus
@Janus: Richtig, du bekommst eine Fehlermeldung, die hässlich ist (obwohl harmlos in der Kommandozeile). Aber trotzdem hätte ich zmv verwenden sollen, das sich um diesen Fall kümmert.
Gilles 'SO - hör auf böse zu sein'
Ich fand dann über -execdirdas ist genial: unix.stackexchange.com/questions/5412/... ich dann festgestellt , dass es etwas hat PATHWahnsinn und war traurig :-(
Ciro Santilli新疆改造中心法轮功六四事件
4

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
Shawn J. Goff
quelle
Dies zeigte sich in der Mitte meines Schreibens des (im Grunde gleichen) Vorschlags:for file in * ; do if [ -d "$file" ] ; then dest="$(echo $file | sed y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/)" ; [ "$dest" != "$file" ] && mv "$file" "$dest" ; fi ; done
Frabjous
Ich habe versucht, es herauszufinden find -type d, konnte es aber nicht ganz verstehen
Michael Mrozek
1
Mein Instinkt wäre das gewesen, um zu 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.
Steven D
Ja, für ... * / wäre besser.
Shawn J. Goff
1
@Shawn: Erwartet 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.
Gilles 'SO - hör auf böse zu sein'
0

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!

Janus
quelle
Kollisionen Überprüfung ist einfach: 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.
Gilles 'SO - hör auf, böse zu sein'
@ Giles. Vielen Dank! Ich habe dich gesehen, mv -inachdem ich das geschrieben habe. Guter Punkt mit dem Zitieren ...
Janus
0

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

Ciro Santilli ist ein Schauspieler
quelle