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.

Bash Default-Verhalten
echo "a b c" | xargs
Output
a b c

Das wirkliche Anwendungsfeld zeigt sich in Kombination mit find: find liefert eine Liste von Pfaden, rm braucht diese Pfade als Argumente.

Bash
find . -name "*.tmp" | xargs rm

Ohne 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.

Bash Whitespace-Falle
printf 'mein bericht.txt\n' | xargs ls
Output
ls: cannot access 'mein': No such file or directory
ls: cannot access 'bericht.txt': No such file or directory

Auch 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.

Bash
find . -name "*.log" -print0 | xargs -0 rm

Faustregel: 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

OptionWirkung
-0NUL als Trennzeichen — Pflicht in Verbindung mit find -print0
-n NMaximal N Argumente pro Aufruf des Befehls
-I {}Replace-String — pro Input genau ein Aufruf, {} wird ersetzt
-P NParallel mit N gleichzeitigen Workern
-r, --no-run-if-emptyBei leerer Eingabe gar keinen Aufruf starten
-tVerbose — zeigt jeden Aufruf vor der Ausführung auf stderr
-pInteractive — fragt vor jedem Aufruf nach Bestätigung
-a FILELiest die Eingabe aus FILE statt von stdin
-L NMaximal N Eingabezeilen pro Aufruf
-d DELIMSetzt 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.

Bash Pro Datei einen Aufruf
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.

Bash Acht parallele Downloads
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.

Bash Alle .tmp löschen
find . -name "*.tmp" -print0 | xargs -0 rm

git + xargs — alle versionierten Dateien nach einem Muster durchsuchen.

Bash TODOs in tracked files
git ls-files | xargs grep -n TODO

Parallel-Downloads mit einer URL-Liste.

Bash Vier parallele wgets
cat urls.txt | xargs -P 4 -n 1 wget -q

Build-Trigger — für jede geänderte Datei einen Befehl ausführen.

Bash Linter pro File
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

/ Weiter

Zurück zu Textverarbeitung

Zur Übersicht