Xargs: Arbeitsverzeichnis vor der Ausführung in Dateipfad ändern?

4

Ich habe einen großen Ordner mit RAR-Archiven. Es gibt eine signifikante Hierarchie von Ordnerebenen. Ich möchte die gesamte Archivsammlung auf einmal entlarven.

Ich habe den folgenden Einzeiler, der funktionieren wird:

find -name "*.rar" -print0 | xargs -0 -n 1 -P 4 unrar x

(Beachten Sie, dass wir vier Threads gleichzeitig ausführen, um den Vorgang zu beschleunigen. :-))

Das Problem bei diesem Befehl ist, dass xargs für jede RAR-Datei im obersten Verzeichnis ausgeführt wird. Dies bedeutet, dass die gesamte Ausgabe in den Ordner der obersten Ebene verschoben wird.

Stattdessen soll die Ausgabe im selben Ordner wie das RAR-Archiv vorhanden sein.

Beispiel:

Top level
 |--FolderA
 |----File1.rar
 |----File2.rar
 |--FolderB
 |----File1.rar
 |----File2.rar
 |----File3.rar
 |--FolderC
 |----File1.rar
 |----File2.rar

Jede der "File1.rar" -Dateien enthält eine Datei mit demselben Namen. Das Extrahieren aller Dateien in den Ordner der obersten Ebene führt daher zu Überschreibproblemen.

Zusammenfassend möchte ich alle RAR-Dateien in der obigen Hierarchie extrahieren. Ich möchte, dass der Inhalt jeder RAR-Datei in dem Ordner vorhanden ist, in dem sich die RAR-Datei befindet.

Es scheint mir, dass die Lösung darin besteht, das Arbeitsverzeichnis irgendwie festzulegen und dann das unrar-Befehlsformular dort auszuführen. Da mir der Befehl find jedoch Dateinamen und keine Verzeichnisse gibt, kann ich so etwas nicht tun

| xargs -I{} -n 1 -P 4 cd {} \; unrar x {}

Gibt es einen besseren Weg, dies zu erreichen, als ein Perl- oder Python-Skript zu schreiben, das den Befehl unrar umgibt und den angegebenen Pfad in seine Teile aufteilt und den Befehl ausführt?

fdmillion
quelle

Antworten:

3

Es gibt Befehle zum Extrahieren eines Verzeichnisnamens ( dirname ) und Dateiname ( basename ) von einem Pfad. Sie könnten also so etwas tun

find . -name '*.rar' -print0 | \
xargs -0 -I{} -n1 -P4 /bin/sh -c 'cd "$(dirname {})"; unrar x "$(basename {})"'

SO VIEL ICH WEISS, xargs Da das Ändern von Verzeichnissen nicht unterstützt wird, benötigen Sie einen Vermittler, um dies zu tun /bin/sh. Sie haben erwähnt, einen Wrapper herumzuschreiben unrar, und das ist im Grunde, was dies tut, außer in Einzeilerform.

jjlin
quelle
Genial! Genau das, was ich brauchte. Vielen Dank!
fdmillion
Dies funktioniert, wenn die Pfadnamen keine Leerzeichen enthalten. Wenn Leerzeichen vorhanden sind, müssen Sie die Anführungszeichen anscheinend auf eine lächerliche Ebene anwählen: 'cd "$ (dirname" {} ")"; unrar x "$ (basename" {} ")" '(ich verwende unzip nicht unrar, aber den gleichen Unterschied)
junichiro
1

Mit GNU Parallel sieht es so aus:

find . -name '*.rar' | parallel cd {//} '&&' unrar x {/}

GNU Parallel ist ein allgemeiner Parallelisierer, mit dem Sie auf einfache Weise Jobs auf demselben Computer oder auf mehreren Computern, auf die Sie ssh-Zugriff haben, parallel ausführen können.

Wenn Sie 32 verschiedene Jobs auf 4 CPUs ausführen möchten, können Sie auf einfache Weise 8 Jobs auf jeder CPU parallelisieren:

Simple scheduling

GNU Parallel erzeugt stattdessen einen neuen Prozess, wenn man fertig ist - die CPUs aktiv zu halten und damit Zeit zu sparen:

GNU Parallel scheduling

Installation

Wenn GNU Parallel nicht für Ihre Distribution gepackt ist, können Sie eine persönliche Installation durchführen, für die kein Root-Zugriff erforderlich ist. Dies kann in 10 Sekunden geschehen:

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

Weitere Installationsoptionen finden Sie unter http://git.savannah.gnu.org/cgit/parallel.git/tree/README

Mehr erfahren

Weitere Beispiele: http://www.gnu.org/software/parallel/man.html

Sehen Sie sich die Intro-Videos an: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Gehen Sie durch das Tutorial: http://www.gnu.org/software/parallel/parallel_tutorial.html

Melden Sie sich für die E-Mail-Liste an, um Unterstützung zu erhalten: https://lists.gnu.org/mailman/listinfo/parallel

Ole Tange
quelle