Login
Newsletter
Werbung

Mo, 24. September 2001, 00:00

xargs(1) - Dein Freund und Helfer

Häufig findet man im Diskussions-Forum Anfragen, die immer auf ein und dasselbe Problem herauslaufen: Man möchte viele Dateien (manchmal über den ganzen Verzeichnisbaum verteilt) gleichartig behandeln. Ob die Dateien nun gelöscht, der Eigentümer oder die Zugriffsrechte gewechselt werden sollen, ist dabei eigentlich egal.

Zumeist wird von der aktiven Forums-Gemeinde die naheliegendste Lösung genannt: Das find(1)-Kommando. Man stelle sich vor, alle Dateien eines in Ungnade gefallenen Users sollen gelöscht werden:

find / -user toelpel -exec rm {} \;

Und an dieser Lösung ist auch nichts Falsches. Sie funktioniert einwandfrei und ist in diesem speziellen Fall auch schnell eingetippt.

Das Problem an dieser Lösung taucht auf, wenn man sehr viele Dateien bearbeiten muss: Pro Datei wird ein eigenes rm(1)-Kommando abgesetzt. Findet find(1) nun 2000 Dateien des Ex-Users toelpel, werden (hintereinander) 2000 Prozesse gestartet, die jeweils nur eine Datei löschen. Auch auf moderneren Rechnern ist das eine nicht zu unterschätzende Last.

Nun muss man sich nur noch daran erinnern, dass rm(1) ja mehrere Dateien auf einmal löschen kann. Also wäre ein einzelnes rm(1)-Kommando mit 2000 Argumenten viel sinnvoller als anders herum.

Genau an dieser Stelle kommt xargs(1) ins Spiel. Die man(1)-Page zu xargs(1) verrrät uns, dass der Sinn und Zweck von xargs(1) "build and execute command lines from standard input" ist, also das Erstellen und Ausführen von Kommandos (mit Hilfe der Daten) aus der Standard-Eingabe.

Ein Beispiel sagt mehr als 1000 Worte:

find / -user toelpel -print | xargs rm

find(1) listet alle Dateien des Users toelpel auf und reicht sie über die Pipe an xargs weiter. xargs(1) nimmt die Liste von der Standardeingabe und bastelt daraus und aus dem rm(1), was ihm als Argument übergeben wurde, ein rm(1)-Kommando mit 2000 Argumenten. Ergebnis: 3 Prozesse anstelle von 2001 Prozessen in der ersten Variante, um 2000 Dateien zu löschen.

"Buh!" hört man da aus dem Publikum rufen, "ich hab's genauso gemacht und es klappt bei ein paar Dateien nicht!" Nun, das kann schon sein - Leerzeichen in Dateinamen sind das Problem. xargs(1) bricht die Dateinamen dort auseinander. Dem ist aber leicht abzuhelfen, wenn man die GNU-Version der benutzten Tools (find und xargs) verwendet. find(1) gibt man bekannt, er möge mit ASCII-NUL beendete Zeichenketten ausgeben, und xargs, er möge solche erwarten:

find / -user toelpel -print0 | xargs -0 rm

Und schon sind die Schwierigkeiten keine mehr. Auf anderen UNIX-Systemen hat man entweder die GNU-Tools auch installiert oder das Nachsehen.

Ein letztes Problem mag noch auftreten. Man stelle sich vor, man möchte die Dateien des Users toelpel doch nicht direkt löschen, sondern erst einmal in ein spezielles Verzeichnis schieben. (Wer weiss, was man noch gebrauchen kann.) Problem: mv(1) erwartet das Zielverzeichnis als letztes Argument, die Dateinamen müssen als erste Argumente angegeben werden. Dieses Problem löst man bei xargs(1) genauso wie bei find(1):

find / -user toelpel -print0 | xargs -0 mv {} /tmp/toelpel-trash

Die Zeichenkombination "{}" zeigt dem xargs(1), an welcher Stelle er die Argumentliste für das Kommando einzufügen hat.

Noch mehr Fragen? "man xargs" und/oder "man find" sollten weiterhelfen.

Viel Spass beim Optimieren Eurer Shellskripte!

Pro-Linux
Pro-Linux @Facebook
Neue Nachrichten
Werbung