Unterschied zwischen "xargs" und Befehlsersetzung?

14

In vielen Fällen verwende ich die Befehlssubstitution anstelle von xargs. Zum Beispiel rm $(ls)ist das gleiche wiels | xargs rm

Was sind wirklich die Unterschiede zwischen ihnen?

Ich denke, einer der Unterschiede ist, dass die Befehlsersetzung in der Subshell ausgeführt wird, während sie xargsin der aktuellen Shell ausgeführt wird, aber ich bin nicht sicher.

Bitte listen Sie die Unterschiede auf.

Sinoosh
quelle

Antworten:

9

Ein Unterschied besteht darin, dass bei Verwendung der Befehlssubstitution anstelle einer Pipe die Größe der übergebenen Daten durch die Größe des Befehlspuffers begrenzt wird, sodass in einigen Fällen keine Warnung ausgegeben wird. Dies bedeutet auch, dass die gesamte Befehlsausgabe erstellt und gespeichert werden muss, bevor sie an den nächsten Befehl übergeben wird. Für große Ausgaben können Sie also viel mehr Speicher als erforderlich verwenden.

Ein weiteres Problem bei der ersten Methode ist, dass die Ausgabe in Leerzeichen aufgeteilt wird, sodass Sie keine Dateinamen mit Leerzeichen verarbeiten können. xargsist ebenfalls vom Leerzeichenproblem betroffen, kann jedoch durch Ändern des verwendeten Trennzeichens behoben werden. Um Dateinamen im Übrigen richtig zu behandeln, müssten Sie im zweiten Beispiel das Null-Byte als Trennzeichen verwenden.

Ein drittes Problem ist, dass Globs erweitert werden. Wenn eine Datei also Sternchen oder Fragezeichen im Namen enthält, kommt es zu unerwarteten Ergebnissen.

Eine nette Diskussion zu diesem Thema finden Sie hier: http://mywiki.wooledge.org/ParsingLs

Die richtige Syntax wäre

echo rm *

oder wenn Sie xargs verwenden müssen,

find . -maxdepth 1 -print0 | xargs -0 echo rm

Entfernen Sie, echowenn die Ausgabe korrekt aussieht.

user000001
quelle
1
@Sinoosh: wird xargsaufgrund der Pipe auch in einer Subshell ausgeführt, sofern Sie dies nicht aktivieren shopt -s lastpipe. In diesem Fall wird die Pipe in der aktuellen Shell ausgeführt. Ich denke nicht, dass das Ausführen in einer Subshell in diesem Fall ein Problem ist, da Sie keine Variablen ändern.
user000001
1
@Sinoosh: Um Argumente nacheinander zu übergeben, können Sie das -lFlag verwenden, z find . -maxdepth 1 -print0 | xargs -0 -l rm. Für die zweite Frage können Sie nicht lsmit verwenden, xargs -0da ls die Ausgabe nicht auf den Nullwert aufteilt, sondern mit Zeilenumbrüchen (die in Dateinamen BTW gültig sind)
user000001
1
@Sinoosh: Nicht der erste, sondern der zweite Absatz: xargs ohne die -0Option leidet unter dem Whitespace-Problem.
User000001
1
Lesen man xargs, echozum Testen verwenden, nicht rm. xargsLassen Sie uns die Shell-Grenzen überschreiten (einige Puffer sind auf 65 KB beschränkt, eine Liste mit Dateinamen nicht).
Waltinator
1
@Sinoosh: Ich habe kein gutes Nachschlagewerk zur Hand, aber Sie können tippen xargs --show-limitsund sehen, welches Limit auf Ihrem System eingestellt ist.
user000001