Dateien eine Ebene nach oben verschieben und den Ordnernamen dem Dateinamen voranstellen?

Dateien eine Ebene nach oben verschieben und den Ordnernamen dem Dateinamen voranstellen?

Test Umgebung:

  • Erstellen Sie Verzeichnisse von 0bis 9und füllen Sie sie mit Dateien von abisz
    $ mkdir {0..9} && touch {0..9}/{a..z}
    
  • Ergebnis von find:
    $ find -type f
    ./0/a
    ./0/b
    
    ...
    
    ./9/y
    ./9/z
    

Wie kann ich die Ausgabe so umwandeln, dass sie folgendermaßen aussieht:

./0a    
./0b

...

./9y
./9z

Antwort1

Mit dem eigenständigen Befehl von Perl rename:

rename -n 's|/||' */*

Wenn alles in Ordnung aussieht, entfernen Sie es -nund löschen Sie anschließend die verbleibenden leeren Verzeichnisse.

rmdir {0..9}

Antwort2

Mit POSIX-Tools

find . -type f -exec sh -c 'for f; do dirn="${f%/*}"; mv -- "$f" "$dirn${f##*/}"; done' sh {} +

findruft eine Shell auf und führt die For-Schleife für jede Datei aus.

  • dirn="${f%/*}"ruft den Namen des übergeordneten Verzeichnisses ab, indem alles ausgeschlossen wird, was nach dem letzten Schrägstrich im Dateinamen steht (und diesen einschließt).

  • ${f##*/}ruft den Dateinamen ohne Pfad ab, indem alles ausgeschlossen wird, was vor (einschließlich) dem letzten Schrägstrich im Dateinamen steht.

Diese beiden Schalenkonstrukte tun dasselbe wiedirnameUndbasename, daher lautet eine äquivalente Form des Befehls

find . -type f -exec sh -c 'for f; do mv -- "$f" "$(dirname "$f")$(basename "$f")"; done' sh {} +

, obwohl dieser langsamer sein sollte, da er für jede Datei zwei zusätzliche Prozesse starten muss.

Wenn Sie nicht in mehr als ein Verzeichnis wechseln müssen, wie in Ihrem Beispiel, genügt eine einfache Shell-Schleife:

for f in */*; do dirn="${f%/*}"; echo mv -- "$f" "$dirn${f##*/}"; done

verwandte Informationen