So kopieren oder verschieben Sie Dateien auf OSX -n-Ebenen über die Shell

430
Alex Starbuck

Wie finde ich alle Dateien eines bestimmten Typs / Namens und kopiere sie -n Ebenen nach oben ? Hier ist die Dateisystem-Baumstruktur:

germany/ | adventure/ | 300x600/ | | | file1.jpg | file2.zip | 400x600/ | file8.jpg file4.zip switzerland/ | adventure/... 

Es gibt viele Länderordner, etwa 20, und die ZIP-Dateien sind nicht unbedingt 3 Ebenen tief. Ich befinde mich zurzeit in ihrem übergeordneten Ordner countries/und möchte alle ZIP- Dateien auf einer Ebene in das adventure/Verzeichnis des entsprechenden Landes / Ordners finden und kopieren .

Ich habe es versucht:

find . -type f -name '*.zip' -exec mv {}/.. \; 

aber dieser versagte kläglich. Es wurde jede Datei um eine Ebene nach oben verschoben, dann wurden diese erneut um eine Ebene nach oben verschoben.

Vielen Dank!

EDIT: Ich habe ein bisschen mit Lösungen aus den Antworten gespielt und viele manSeiten gelesen :). Schließlich akzeptierte ich die Lösung, die mir am besten gefallen hat, da sie elegant und unabhängig von der Schale ist.

Ich versuche immer noch herauszufinden:

  1. Funktioniert findals Schleife oder werden geschweifte Klammern in anderen Programmiersprachen als "Liste / Array" behandelt? Das bedeutet: Wird es mit den gefundenen Ergebnissen (dh Zeichenfolgen) auf einmal gefüllt und DANN an den Befehl weitergegeben -exec?
  2. Warum passierte der Zug zuerst eine Ebene nach oben, dann wieder eine Ebene nach oben?
  3. Gibt es eine Möglichkeit, sofort mitzuteilen mv/cp, ob -n-Ebenen [auf / ab] gehen sollen?
2

3 Antworten auf die Frage

0
Phillip -Zyan K Lee- Stockmann

versuchte es mit Ubuntu zsh 5.0.2:

for pdir in */ do cd $pdir for dir in */ do cd $dir mv */*.zip . cd .. done cd .. done 
Schließen. Ich möchte, dass alle .zip-Dateien zwei Ebenen höher liegen, dh im `adventure /` -Unterverzeichnis des `germany /` -Verzeichnisses. Es gibt auch andere Verzeichnisse, die nach Ländernamen benannt sind. Daher möchte Id für all diese einen Befehl ausgeben können (z. B. Österreich / Deutschland / Deutschland). Vielen Dank Alex Starbuck vor 7 Jahren 0
ok - lass es mich nochmal versuchen - aber wieder kein zsh, um es zu bestätigen ;-) Phillip -Zyan K Lee- Stockmann vor 7 Jahren 0
Ich habe dies in einem Ubuntu LXC Container und mit Zsh 5.0.2 versucht. Sollte wie ein Zauber wirken ;-) Phillip -Zyan K Lee- Stockmann vor 7 Jahren 0
Dies sollte funktionieren, jedoch nur für ein Verzeichnis auf der Stammebene (z. B. "Deutschland"), nicht für alle. slhck vor 7 Jahren 0
Wie wäre es jetzt? :-D Phillip -Zyan K Lee- Stockmann vor 7 Jahren 0
0
slhck

Sie können es shell-unabhängig machen und es zu einem findBefehl zusammenfassen:

find . -type f -name '*.zip' -exec \ sh -c 'echo cp -- "$0" "$(dirname "$0")"/..' {} \; 

Entfernen Sie das, echowenn Sie sicher sind, dass es das tut, was Sie möchten.

Verwenden Sie finddiese Option, um die Dateien zu suchen. Führen Sie eine Shell mit aus -exec sh -c, und übergeben Sie die gefundene Datei mit {}dem ersten Argument an diese Shell. Der Shell steht daher der Dateipfad als zur Verfügung $0.

Sie können dann dirname "$0"und einen Befehl substitution ( $(…)) verwenden, um das übergeordnete Verzeichnis der Datei abzurufen. Hängen Sie so viele an, /..wie Sie höher reisen möchten.

Beachten Sie, dass ich zitierte die Dateinamen von Dateien mit Zeilenumbrüche oder Leerzeichen im Namen zu verhindern, nicht ordnungsgemäß erweitert aus ist.

Randbemerkung: In Ihrer Frage sagen Sie, dass Sie "kopieren" möchten, aber später verwenden Sie den Befehl "mv". Ich nahm an, Sie wollten Dateien kopieren, wie der Titel und die Einleitung sagen. slhck vor 7 Jahren 0
Ich habs! "mv" oder "cp" spielt keine Rolle, ich kann beide verwenden und handhaben :). `Find` findet also die Pfade zu .zip-Dateien und füllt das` {} `" Objekt "mit Ergebnissen. `-exec` führt` sh -c` mit der Option 'read from string' (-c) aus, die zwei Argumente "definiert" (?) - das erste Argument wird zuerst `path / to / file.zip` aus den Ergebnissen` { } `. Dann extrahieren Sie das Elternverzeichnis der Datei, gehen Sie eine Ebene höher und gehen Sie die `cp`-Datei hoch. Richtig? Alex Starbuck vor 7 Jahren 0
Ja, das ist so ziemlich alles, was hier los ist! Der `sh`-Aufruf hat in diesem Fall zwei Argumentoptionen, eine ist` -c "cmd" (= "nimmt die auszuführenden Befehle aus der folgenden Zeichenfolge"), und die zweite ist `{}` - wie Sie richtig sagen - der Pfad zur ersten gefundenen Datei, dann in der zweiten Schleife die zweite Datei usw. Dieser `-exec sh -c" ... "` Ansatz ist ziemlich nützlich für komplexere `find`-Skripts, d müssten sonst ein paar loops schreiben. slhck vor 7 Jahren 0
Könnten Sie noch etwas näher erläutern - ich bin verwirrt über die Saite. Es gibt einen Befehl (cp) und danach folgen zwei Variablen ($ 0 und $ (...)). Wie funktioniert das intern? Wie landet der vollständige Pfad / zur / -Datei in $ 0 und darauf wird ein anderer Befehl Verzeichnisname angewendet? Vielen dank! Alex Starbuck vor 7 Jahren 0
"$ 0" ist das erste Argument, das an "sh -c" übergeben wird ... ". Sie können 'sh -c' echo $ 0 $ 1 $ 2 'foo bar baz' ausführen und erhalten als Ausgabe 'foo bar baz'. In Ihrem Fall war das erste Argument "{}", wobei "find" durch den Pfad zur gefundenen Datei ersetzt wird. Das erste Argument für `cp` ist also der Pfad zur Datei. Das zweite Argument muss der übergeordnete Ordner der Datei sein, daher müssen wir zuerst den Ordnernamen abrufen. slhck vor 7 Jahren 0
Dazu wird der Befehl `dirname" $ ​​0 "` ausgeführt. Ihre Ausgabe ist offensichtlich nur das Verzeichnis der Datei. Die Ausgabe des Befehls wird wortwörtlich dahin gesetzt, wo das zweite Argument für "cp" steht - das ist Befehlssubstitution (siehe den Link oben). Die Befehlsersetzung wird * vor * dem Rest der Zeile durchgeführt. Dies ist sehr nützlich, wenn Sie möchten, dass Ihr Shell-Befehl die Ausgabe eines anderen Befehls enthält. `$ (Dirname" $ ​​0 ")` ist also im abschließenden Befehl `/ path / to / folder`, an den wir einfach` / .. `anhängen, um den übergeordneten Ordner zu erhalten. slhck vor 7 Jahren 0
Ich habs! Es ist nur so, dass mir die Syntax seltsam vorkommt. Finden Sie, dann Optionen, dann sh, dann Argument zu sh und am Ende wieder etwas, das mit "funktioniert" (geschweifte Klammern). Ich denke, das ist nur etwas. sich einprägen ;) Alex Starbuck vor 7 Jahren 0
0
Matija Nalis

Nur die schnelle Alternative, wenn die Realität so einfach ist wie das gegebene Beispiel:

cd germany mv */*/*.zip . 

(und es gibt keine Millionen von Dateien)

Wie in einem Kommentar oben erwähnt, möchte das OP dies für * jeden * Ordner tun, nicht nur für "Deutschland". Sie benötigen also eine Schleife über alle Ordner. slhck vor 7 Jahren 0
Ja, ich muss das für alle "Länder" -Ordner tun, nicht nur für einen Ordner, und ich bin nicht sicher, dass die ZIP-Dateien immer drei Ebenen tief sind. Danke trotzdem ;) Alex Starbuck vor 7 Jahren 0