Manchmal stößt man auf Linux Verzeichnisse, die so viele Dateien enthalten, dass man sie nicht mehr löschen kann.
Zum Beispiel:
$ rm * bash: /bin/rm: Argument list too long $
Dies ist ein Fall für den xargs
-Befehl. Mit diesem wenig bekannten Linux-Kommando kann man Befehle für beliebig viele Parameter aufrufen. Der auszuführende Befehl wird - ggf. mit weiteren Parametern - seinerseits dem xargs
-Befehl als Parameter übergeben. Alle zusätzlichen Parameter, wie z.B. ein paar hunderttausend zu löschende Dateinamen, liest xargs
dann von stdin ein. Der Befehl wird dann nur mit sovielen Parametern aufgerufen, wie unter Linux zulässig ist. Falls in der Kommandozeile auch weitere Parameter angegeben wurden, dann werden diese Parameter ebenfalls verwendet, die zusätzlichen Parameter von stdin kommen immer danach.
Konkret sieht das so aus:
$ find . | xargs rm
Der find .
Befehl listet alle Dateien im aktuellen Verzeichnis. Durch das Pipe-Symbol wird das Listing dem xargs
-Kommando übergeben, welches dann seinerseits das rm
-Kommando ggf. mehrfach aufruft.
Kopieren
Etwas schwieriger ist das Kopieren von sehr vielen Dateien in ein Ziel-Directory. Wenn man find . | xargs cp (Ziel)
eingibt, funktioniert es nicht wie erhofft, da ja die Parameter für die zu kopierenden Dateien angehängt werden, d.h. das Ziel-Verzeichnis ist der erste Parameter und nicht der letzte.
Glücklicherweise gibt es für die cp
- oder mv
-Befehle den Parameter -t
oder --target-directory=
. Die korrekte Syntax sieht also so aus:
$ find . | xargs cp --target-directory=/home/mydata
Kopieren von Dateien mit Leerzeichen
Richtig interessant wird es, wenn man Dateien kopieren will, die Leerzeichen oder andere spezielle Zeichen enthalten. Leerzeichen werden von xargs
nämlich als Trennzeichen aufgefasst:
$ ls -la total 8 drwxr-xr-x 2 u00 u00 4096 Feb 27 18:39 . drwxr-xr-x 12 u00 u00 4096 Feb 27 18:38 .. -rw-r--r-- 1 u00 u00 0 Feb 27 18:39 Datei eins -rw-r--r-- 1 u00 u00 0 Feb 27 18:39 Datei zwei $ find . -type f | xargs ls -l ls: ./Datei: No such file or directory ls: eins: No such file or directory ls: ./Datei: No such file or directory ls: zwei: No such file or directory
Um dies zu umgehen, kann man xargs
veranlassen, das NUL-Zeichen (hexadezimal 0x00) als Trennzeichen zu verwenden. Natürlich muss das Programm, welches die Parameterliste generiert, ebenfalls das NUL-Zeichen verwenden.
Bei find
sieht das dann so aus:
$ find . -print0 -type f | xargs -0 ls -l -rw-r--r-- 1 u00 u00 0 Feb 27 18:39 ./Datei eins -rw-r--r-- 1 u00 u00 0 Feb 27 18:39 ./Datei zwei
Falls das Tool keine Option -0
hat, muss man on-the-fly die NUL-Zeichen einbauen. Man ersetzt z.B. die Line Feeds mit Hilfe eines regulären Ausdrucks, am besten mit Perl:
$ find . -type f | perl -pe 's,\n,\0,' | xargs -0 ls -l -rw-r--r-- 1 u00 u00 0 Feb 27 18:39 ./Datei eins -rw-r--r-- 1 u00 u00 0 Feb 27 18:39 ./Datei zwei
1 Comment
Anonymous
Als Alternative ohne PERL - z.B. falls ein abgespecktes Linux (z.B. BusyBox) installiert ist:
Der Pfad wird dabei komplett in doppelte Anführungszeichen gesetzt. Das .* wählt als Wildcard sämtlichen Input der Standardeingabe und das & gibt die Standardeingabe zurück.
Und ein konkretes Anwendungsbeispiel zum Aufspüren von Duplikaten seiner geliebten Musiksammlung :
md5sum erzeugt einen MD5-Hashwert und liest die Standardeingabe als Binärdatei (-b). grep -v sortiert alle Zeilen aus, welche die Zeichenketten ".Apple" , "Thumbs.db", "esktop.ini" oder ":eDS_Store" enthalten; die schönen Relikte des Eigenlebens unserer unserer fleißigen Betriebssysteme. Das Resultat wird mittels > in die Datei CHECKSUM.txt geschrieben. Diese kann hinterher wunderbar ausgewertet werden. Auf der Kommandozeile oder auch in Excel... Natürlich können auch zwei txt-Dateien über zwei unterschiedliche Verzeichnisse erzeugt werden, die sich über die Zeit etwas chaotisch mit Musikdateien gefüllt haben. Im Anschluss vergleicht man dann die Inhalte der Dateien z.B. mittels diff ...oder eben Excel
.
Greets florus