Übergabe mehrerer Parameter über xargs

15

Ich möchte in der Lage sein xargs, mehrere Parameter in verschiedenen Teilen eines Befehls auszuführen.

Zum Beispiel Folgendes:

echo {1..8} | xargs -n2 | xargs -I v1 -I v2 echo the number v1 comes before v2

Ich würde hoffen, dass es zurückkehren würde

the number 1 comes before 2
the number 3 comes before 4 

... usw

Ist das erreichbar? Ich vermute, dass meine mehrfache Verwendung von -Ifalsch ist.

Damien Sawyer
quelle

Antworten:

27

Ich glaube, dass Sie so nicht verwenden -Ikönnen. Sie können jedoch den gewünschten Effekt / das gewünschte Verhalten erzielen, indem Sie sagen:

echo {1..8} | xargs -n2 sh -c 'echo "the number $1 comes before $2"' sh

Dadurch wird im Wesentlichen ein einzeiliges Ad-hoc -Shell-Skript erstellt, das xargsüber ausgeführt wird sh -c. Die beiden Werte, xargsdie aus der Eingabe heraus analysiert werden, werden an dieses „Skript“ übergeben. Die Schale weist dann diese Werte $1und $2, die Sie dann im „Script“ verweisen können.

Scott
quelle
3
Danke - das ist großartig. Ich habe den Mann für sh gelesen und habe Schwierigkeiten zu verstehen, was der zweite Aufruf an sh bewirkt und warum seine Auslassung "die Hälfte" des Ergebnisses ergibt.
Damien Sawyer
4
@ DamienSawyer Es gibt keinen zweiten Anruf bei sh. Das Nachlaufen sham Ende ist das, worauf gesetzt wird $0. $0ist normalerweise das, was den Namen des Interpreters oder des Skripts enthält.
Kusalananda
Ich habe gerade das Trailing ersetzt, shmit echo $shdem es funktioniert. Final shfungiert also als Platzhalter
kenn
Nun, das ist eine Vereinfachung dessen, was Kusalananda gesagt hat.
Scott
5

Im konkreten Fall von printfkönnen Sie immer Folgendes tun:

echo {1..8} | xargs printf 'the number %s comes before %s\n'

weil printfeine intrinsische xargs-ähnlichen Fähigkeit mehrfach auszuführen , wenn es mehr Argumente gegeben ist , als es für einen einzelnen Aufruf benötigt. Das hat aber wenig Vorteil gegenüber

printf 'the number %s comes before %s\n' {1..8}

Bei großen Listen kann der einfache xargsBefehl dazu führen xargs, dass mehrere Instanzen von ausgeführt werden printf, von denen einige möglicherweise eine ungerade Anzahl von Argumenten enthalten. Sie könnten zu gehen, -n 1000um sich dagegen xargszu schützen, wobei 1000 eine gerade Zahl ist, die klein genug sein sollte, um die zu lange Grenze der Arg-Liste nicht zu erreichen , und groß genug, um zu vermeiden, dass so viele printfs ausgeführt werden.

Beachten Sie, dass bei jedem Aufruf in einem separaten neuen Prozess xargsnicht die integrierte printf, sondern die externe Shell aufgerufen printfwird.

Beachten Sie auch, dass eine leere Eingabe, außer bei einigen BSDs, immer noch printfeinmal ohne Argument ausgeführt wird. GNU xargsund kompatibel haben eine -r (oder --no-run-if-empty) Option, um dies zu vermeiden.

Um es klar auszudrücken, diese einfache Antwort ist spezifisch für Ihr printfBeispiel und würde in dem allgemeinen Fall nicht funktionieren, in dem Sie zwei Parameter gleichzeitig an Ihren Befehl übergeben müssen (wie dies beispielsweise der Fall wäre diff). Um das allgemeine Problem mit zu lösen zsh, können Sie verwenden:

for i j ({1..8}) echo "the number $i comes before $j"
Stéphane Chazelas
quelle
(1) IMHO ist der zshTeil des oben Gesagten eine echte Antwort, und der xargsTeil ohne Optionen ist nur eine Kuriosität. In einem solchen Fall würde ich in Betracht ziehen, die eigentliche Antwort an die erste Stelle zu setzen. (2) Ich gehe davon aus, dass Sie einen Grund haben, in Ihrem Befehl keine Anführungszeichen zu verwenden zsh. Wenn ja, möchten Sie es vielleicht sagen, damit die Leute das Obige nicht lesen und anfangen zu denken, dass Zitate nicht wichtig sind. (Oder schließen Sie sie einfach ein, da sie nicht weh tun.)
Scott
Das ist wirklich cool. Ich landete hier und suchte nach etwas Ähnlichem, bei dem ich mir nicht sicher war, wie viele Argumente ich erhalten würde, die in die Befehlszeile des nächsten Args eingegeben werden mussten. tat so etwas wieawk -F'\t' '/match/{printf $1"\0"$2"\0"}' | xargs -0 printf -- '-args1 "%s" -args2 "%s"' | xargs mycommand
keithpjolley
@keithpjolley, Ihre Verwendung von -0auf der ersten xargs, um es zuverlässiger zu machen, wird dadurch besiegt, dass Sie es auf der zweiten nicht verwenden. Das erste Argument für printf(sowohl das eigenständige Dienstprogramm als auch awkdie printf()Funktion) ist das Format. Sie sollten dort keine Variablen verwenden. Hier könnten Sie tun awk -F'\t' '/match/{printf "-args1\0%s\0-args2\0%s\0", $1, $2}' | xargs -n400 -r0 mycommand. Erneut -n400erforderlich, um sicherzustellen, dass xargseine Reihe von Argumenten übergeben wird, die ein Vielfaches von 4 ist (beachten Sie, dass nicht alle awkImplementierungen die Verwendung \0dieser Argumente hier unterstützen).
Stéphane Chazelas
habe es nicht verwendet -0, um es zuverlässiger zu machen, habe es verwendet, um es tun zu lassen, was ich tun wollte, was es tut.
Keithpjolley
2

Versuche dies:

echo {1..8} |xargs -n 2 bash -c 'echo "the number $0 comes before $1"'
md11235
quelle
2
Dies würde in diesem Fall funktionieren, aber es ist besser, ein sh -cSkript mit sh(oder was auch immer) in auszuführen $0. Beachten Sie, dass dies $0nicht enthalten ist, $@wenn dies vom sh -cSkript verwendet werden soll, z. B. wenn das Skriptecho "the two numbers were $@"
Kusalananda