xargs ist die Brücke zwischen einer Pipeline und Befehlen, die ihre Eingabe nicht von stdin lesen. Viele Tools — rm, mv, cp, kill, grep — erwarten ihre Ziele als Argumente auf der Kommandozeile, nicht als Datenstrom. xargs liest Zeilen oder durch NUL getrennte Tokens und reicht sie als Argumentliste an einen Befehl weiter. Damit wird find ... | xargs rm zu einem der meistgenutzten Idiome überhaupt.
Was xargs macht
xargs liest Daten von stdin, zerlegt sie in Tokens und ruft damit einen Befehl auf — die Tokens werden dabei als Argumente an den Befehl angehängt. Ohne expliziten Befehl ist der Default echo.
echo "a b c" | xargsa b cDas wirkliche Anwendungsfeld zeigt sich in Kombination mit find: find liefert eine Liste von Pfaden, rm braucht diese Pfade als Argumente.
find . -name "*.tmp" | xargs rmOhne xargs würde rm die Pfade aus der Pipe nicht annehmen — rm liest schlicht keine stdin. xargs macht aus dem Datenstrom eine Argumentliste.
Standardverhalten
Per Default trennt xargs an Whitespace und Zeilenumbrüchen. Das ist im Alltag die häufigste Fehlerquelle: Sobald ein Dateiname ein Leerzeichen enthält, wird er von xargs in zwei Argumente zerlegt.
printf 'mein bericht.txt\n' | xargs lsls: cannot access 'mein': No such file or directory
ls: cannot access 'bericht.txt': No such file or directoryAuch Anführungszeichen werden von xargs interpretiert — was bei rohen Dateinamen fast immer unerwünscht ist. Die Lösung sind NUL-getrennte Eingaben, die mit find -print0 und xargs -0 zusammenarbeiten.
Sicheres Idiom mit -0
Das verlässliche Muster für alle Skripte: find gibt mit -print0 die Pfade durch NUL-Bytes getrennt aus, xargs -0 liest diese Tokens und behandelt alles dazwischen als Teil eines Pfades — Leerzeichen, Tabs, Newlines inklusive.
find . -name "*.log" -print0 | xargs -0 rmFaustregel: Wenn die Eingabe Dateinamen enthält, immer -print0/xargs -0. Nur bei reinen ASCII-Tokens ohne Whitespace (z. B. PIDs aus pgrep) darfst du auf das Default-Verhalten vertrauen.
Wichtige Optionen
| Option | Wirkung |
|---|---|
-0 | NUL als Trennzeichen — Pflicht in Verbindung mit find -print0 |
-n N | Maximal N Argumente pro Aufruf des Befehls |
-I {} | Replace-String — pro Input genau ein Aufruf, {} wird ersetzt |
-P N | Parallel mit N gleichzeitigen Workern |
-r, --no-run-if-empty | Bei leerer Eingabe gar keinen Aufruf starten |
-t | Verbose — zeigt jeden Aufruf vor der Ausführung auf stderr |
-p | Interactive — fragt vor jedem Aufruf nach Bestätigung |
-a FILE | Liest die Eingabe aus FILE statt von stdin |
-L N | Maximal N Eingabezeilen pro Aufruf |
-d DELIM | Setzt einen eigenen Delimiter (z. B. -d '\n' für reine Zeilenmodi) |
-r ist besonders wichtig in Skripten: Ohne diese Option startet xargs den Befehl auch dann, wenn stdin leer ist — was Aufrufe wie xargs rm unangenehm machen kann (erwartet ein Argument, bekommt keins, beschwert sich).
Replace-String mit -I
Per Default hängt xargs alle Eingabe-Tokens an einen Befehlsaufruf — gut für Performance, aber nicht immer das, was du willst. Mit -I {} definierst du einen Platzhalter, der pro Eingabezeile genau einmal ersetzt wird. Das Resultat: ein Befehl pro Input.
find . -name "*.bak" -print0 | xargs -0 -I {} mv {} backup/Der Platzhalter ist frei wählbar — {} ist Konvention (analog zu find -exec), aber -I FILE mit mv FILE backup/ funktioniert genauso. -I impliziert immer -n 1, ist also langsamer, aber praezise und gut lesbar.
Parallelisierung mit -P
xargs -P N startet bis zu N Befehle gleichzeitig. Das ist der pragmatischste Weg, Bulk-Operationen auf vielen Dateien zu beschleunigen — ohne make, ohne parallel, mit Bordmitteln.
cat urls.txt | xargs -P 8 -n 1 wget -q-n 1 sorgt dafür, dass jeder wget-Aufruf eine URL bekommt; -P 8 lässt acht davon nebeneinander laufen. Bei CPU-gebundener Arbeit wählst du N typischerweise als Anzahl der Kerne, bei IO-gebundener Arbeit (Downloads, Netzwerk) gerne deutlich mehr.
Achtung: Die Reihenfolge der Outputs ist bei -P > 1 nicht mehr garantiert — Zeilen verschiedener Prozesse können sich auf stdout vermischen.
Praxis
find + xargs ist das klassische Bulk-Löschen oder -Verschieben. Mit -print0/-0 immer sicher gegen Whitespace.
find . -name "*.tmp" -print0 | xargs -0 rmgit + xargs — alle versionierten Dateien nach einem Muster durchsuchen.
git ls-files | xargs grep -n TODOParallel-Downloads mit einer URL-Liste.
cat urls.txt | xargs -P 4 -n 1 wget -qBuild-Trigger — für jede geänderte Datei einen Befehl ausführen.
git diff --name-only --diff-filter=AM | xargs -I {} eslint {}Typische Fallen
Whitespace ohne -0 ist kaputt
Sobald ein Dateiname ein Leerzeichen, einen Tab oder ein Newline enthält, zerlegt xargs ihn in mehrere Argumente. Das Ergebnis sind Aufrufe wie rm mein bericht.txt — zwei separate Argumente, beide existieren nicht. Die einzige verlässliche Kombination ist find ... -print0 | xargs -0 .... In Skripten gibt es keinen guten Grund, ohne -0 zu arbeiten.
-n 1 startet einen Prozess pro Input — langsam
Wenn du mit xargs -n 1 jeden Eintrag in einen separaten Aufruf zwingst, startet die Shell pro Datei einen kompletten Prozess. Bei tausenden Dateien dauert das spuerbar. Zum Vergleich: find -exec cmd {} + (mit + am Ende) bündelt Argumente bis zum ARG_MAX-Limit und ist deutlich schneller. xargs ohne -n 1 macht genau dasselbe.
-r vermeidet Aufrufe bei leerem Input
Ohne -r ruft xargs den Befehl auch dann auf, wenn stdin nichts geliefert hat — find . -name "*.gibt-es-nicht" | xargs rm startet rm ohne Argumente und produziert eine Fehlermeldung. --no-run-if-empty (kurz -r) verhindert das. Auf GNU-Systemen ist es eine Option, die du standardmäßig setzen solltest.
-I impliziert -n 1
Sobald du den Replace-String -I {} benutzt, schaltet xargs automatisch in den Modus „ein Aufruf pro Input”. Du verlierst damit die Bulk-Performance des Defaults. Wenn dir das wichtig ist und du dennoch ersetzen willst, ist GNU parallel mit {} die schnellere Alternative.
Reihenfolge bei -P nicht garantiert
Parallele Worker schreiben gleichzeitig auf stdout. Zeilen können sich vermischen, und die Reihenfolge der Outputs entspricht nicht zwingend der Reihenfolge der Inputs. Wenn die Reihenfolge wichtig ist, lass -P weg oder pipe die Outputs in separate Dateien (-I {} plus > log_{}.txt).
ARG_MAX-Limit der Shell
Eine direkte Kommandozeile rm * scheitert bei zigtausenden Dateien an ARG_MAX (dem Kernel-Limit für Argumentlänge plus Umgebung). xargs ist genau dafür gebaut: Es splittet die Eingabe automatisch in mehrere Aufrufe, sodass jeder einzelne unter ARG_MAX bleibt. Damit ist find ... | xargs rm auch bei riesigen Verzeichnissen sicher.
Weiterführende Ressourcen
Externe Quellen
- xargs(1) – Linux manual page (man7.org) — offizielle Dokumentation aller Optionen
- GNU findutils Manual: xargs — ausführliche Beschreibung im GNU-Handbuch
- Arch Wiki: Core utilities — Übersicht über xargs und verwandte Werkzeuge
Verwandte Artikel
- find – Dateien suchen — der typische Partner von xargs
- GNU parallel — maechtige Alternative für Parallelisierung
- tr – Zeichen ersetzen — oft als Vorstufe zu xargs eingesetzt
- sed – Stream Editor — Textmanipulation in Pipelines
- ln – Links anlegen — typischer Bulk-Anwendungsfall mit xargs