Verschieben und umbenennen, indem Sie die Ausgabe von find analysieren

825
Canaryyellow

Ich habe verschachtelte Verzeichnisse von PDF-Dateien und möchte sie in ein Verzeichnis höherer Ebene extrahieren, indem Sie sie wie folgt umbenennen:

Meine Dateien sind ungefähr so:

./path1/pathA/fileI.pdf ./path1/pathB/fileII.pdf 

Ich möchte erreichen:

./path1_pathA_fileI.pdf  ./path1_pathB_fileII.pdf 

Ich weiß, dass ich eine Liste der Dateien erstellen kann

find . -type f -name "*.pdf"

Und ich kann mir eine Lösung vorstellen

find . -type f -name "*.pdf" | mv -t ...

Aber ich weiß nicht, wie ich das ausfüllen soll, weil ich das Parsing und die Variablenzuweisung in Bash nicht verstehe. Wie teilt man den Pfad am '/' auf und bildet einen neuen Pfad und Dateinamen wie oben?

Vielen Dank im Voraus!

4

1 Antwort auf die Frage

6
John1024

Versuchen:

find . -mindepth 2 -type f -name '*.pdf' -exec bash -c 'f=$; mv "$1" "./$"' None {} \; 

Dies ist sicher für alle Dateinamen, auch für Dateinamen, deren Namen Zeilenumbrüche enthalten.

Wie es funktioniert

  • -mindepth 2

    Dies weist find an, keine Dateien zu verarbeiten, die sich bereits im aktuellen Verzeichnis befinden.

  • -type f -name '*.pdf'

    Dies beschränkt die Suche auf reguläre Dateien mit der pdfErweiterung.

  • -exec bash -c '...' None {} \;

    Dadurch wird der Befehl in der in Anführungszeichen stehenden Zeichenfolge ausgeführt, wobei der Dateiname als erstes Argument angegeben wird $1.

    Für unsere Zwecke ist die Zeichenfolge Noneeinfach ein Platzhalter. Es wird zugewiesen $0, unter bash Konventionen, ist der Name des Befehls, wir laufen.

  • f=$; mv "$1" "./$"

    (A) entfernt das Präfix ./vom Dateinamen und (b) verschiebt die Datei an den gewünschten Ort mit dem neuen Namen.

    $ist ein Beispiel für die Entfernung von bash Präfixen . Es gibt die strign $1mit ./von Anfang an entfernt. $ist ein Beispiel für die Mustersubstitution von bash . Es gibt den String zurück, $fwobei alle mit /ersetzt werden _. Um mehr über diese Funktionen zu lesen, finden Sie im Abschnitt in dem man bashTitel Parameter Expansion .

Effizientere Version

Die obige Version ruft bash für jede gefundene Datei auf. Alternativ können Sie bash nur einmal für mehrere gefundene Dateien aufrufen. Dazu wickeln wir unseren Befehl in eine forSchleife:

find . -mindepth 2 -type f -name '*.pdf' -exec bash -c 'for f in "$@"; do f=$; echo mv "$f" "./$"; done' None {} + 

Alternatives Problem

Angenommen, alle Dateien, die wir benötigen, befinden sich in einem Verzeichnis der zweiten Ebene, und wir möchten, dass die verschobenen Dateien in der Reihenfolge der Verzeichnisnamen umgekehrt werden, so dass ./path1_pathA_fileI.pdfwir statt mit enden ./pathA_path1_fileI.pdf. In diesem Fall:

for d1 in */; do d1=$; for d2 in "$d1"/*/; do d2=$; p="$_$d1"; for f in "./$d2"/*.pdf; do echo mv "$f" "./$_$"; done; done; done 

Oder für diejenigen, die es bevorzugen, dass ihre Befehle über mehrere Zeilen verteilt sind:

for d1 in */ do d1=$ for d2 in "$d1"/*/ do d2=$ p="$_$d1" for f in "./$d2"/*.pdf do echo mv "$f" "./$_$" done done done 
Danke für die schrittweise Panne! Was wäre, wenn ich auch die Reihenfolge der beiden Dir-Strings ändern wollte, so dass der letzte Pfad lautet ./pathA_path1_fileI.pdf In diesem Fall funktioniert die Mustersubstitution $ nicht. Wie kann das gemacht werden? Canaryyellow vor 7 Jahren 0
@Canaryyellow OK. Ich habe dafür Code hinzugefügt. John1024 vor 7 Jahren 0