Mir scheint, dass alle auf dieser Seite vorhandenen Antworten falsch sind, einschließlich der als richtig gekennzeichneten. Das liegt daran, dass die Frage nicht eindeutig formuliert ist.
Zusammenfassung: Wenn Sie den Befehl "genau einmal für jede angegebene Eingabezeile" ausführen möchten und die gesamte Zeile (ohne die neue Zeile) als einzelnes Argument an den Befehl übergeben möchten , ist dies die beste UNIX-kompatible Methode:
... | tr '\n' '\0' | xargs -0 -n1 ...
GNU verfügt xargs
möglicherweise über nützliche Erweiterungen, mit tr
denen Sie diese beseitigen können. Sie sind jedoch unter OS X und anderen UNIX-Systemen nicht verfügbar.
Nun zur langen Erklärung…
Bei der Verwendung von xargs sind zwei Punkte zu berücksichtigen:
- Wie teilt es die Eingabe in "Argumente" auf? und
- Wie viele Argumente müssen gleichzeitig den untergeordneten Befehl übergeben werden?
Um das Verhalten von xargs zu testen, benötigen wir ein Dienstprogramm, das anzeigt, wie oft es ausgeführt wird und mit wie vielen Argumenten. Ich weiß nicht, ob es dafür ein Standarddienstprogramm gibt, aber wir können es ganz einfach in bash codieren:
#!/bin/bash
echo -n "-> "; for a in "$@"; do echo -n "\"$a\" "; done; echo
Angenommen, Sie speichern es show
in Ihrem aktuellen Verzeichnis und machen es ausführbar. So funktioniert es:
$ ./show one two 'three and four'
-> "one" "two" "three and four"
Wenn es sich bei der ursprünglichen Frage wirklich um Punkt 2 oben handelt (wie ich denke, nachdem ich sie einige Male gelesen habe) und sie so zu lesen ist (Änderungen in Fettdruck):
Wie kann ich xargs den Befehl genau einmal für jedes ausführen Argument gegeben Eingabe? Das Standardverhalten besteht darin, die Eingabe in Argumente zu unterteilen und den Befehl so oft wie möglich auszuführen , wobei jeder Instanz mehrere Argumente übergeben werden.
dann ist die Antwort -n 1
.
Vergleichen wir das Standardverhalten von xargs, bei dem die Eingabe um Leerzeichen aufgeteilt wird und der Befehl so oft wie möglich aufgerufen wird:
$ echo one two 'three and four' | xargs ./show
-> "one" "two" "three" "and" "four"
und sein Verhalten mit -n 1
:
$ echo one two 'three and four' | xargs -n 1 ./show
-> "one"
-> "two"
-> "three"
-> "and"
-> "four"
Wenn sich die ursprüngliche Frage andererseits auf Punkt 1 bezog und die Aufteilung der Eingaben so war (viele Leute, die hierher kommen, scheinen zu glauben, dass dies der Fall ist, oder verwechseln die beiden Probleme):
Wie kann ich xargs veranlassen, den Befehl mit genau einem Argument für jede angegebene Eingabezeile auszuführen ? Das Standardverhalten besteht darin, die Zeilen um Leerzeichen zu teilen .
dann ist die Antwort subtiler.
Man würde denken, dass -L 1
dies hilfreich sein könnte, aber es stellt sich heraus, dass es das Parsen von Argumenten nicht ändert. Der Befehl wird für jede Eingabezeile nur einmal ausgeführt, mit so vielen Argumenten, wie in dieser Eingabezeile vorhanden waren:
$ echo $'one\ntwo\nthree and four' | xargs -L 1 ./show
-> "one"
-> "two"
-> "three" "and" "four"
Nicht nur das, sondern wenn eine Zeile mit Leerzeichen endet, wird sie an die nächste angehängt:
$ echo $'one \ntwo\nthree and four' | xargs -L 1 ./show
-> "one" "two"
-> "three" "and" "four"
Es geht natürlich -L
nicht darum, die Art und Weise zu ändern, in der xargs die Eingabe in Argumente aufteilt.
Das einzige Argument, das dies plattformübergreifend tut (ausgenommen GNU-Erweiterungen), ist -0
die Aufteilung der Eingabe auf NUL-Bytes.
Dann geht es nur noch darum, Zeilenumbrüche mit Hilfe von tr
: in NUL zu übersetzen :
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 ./show
-> "one " "two" "three and four"
Jetzt sieht die Argumentanalyse gut aus, einschließlich des nachgestellten Leerzeichens.
Wenn Sie diese Technik mit kombinieren -n 1
, erhalten Sie genau eine Befehlsausführung pro Eingabezeile, unabhängig von Ihrer Eingabe. Dies kann eine weitere Möglichkeit sein, die ursprüngliche Frage zu betrachten (möglicherweise die intuitivste, wenn man den Titel bedenkt):
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show
-> "one "
-> "two"
-> "three and four"
find /path -type f -delete
wäre noch effizienter :)