So geben Sie dem nächsten Befehl eine durch Kommas getrennte Liste als Argumente


9

Ich habe ein Skript s1, das eine Liste von Zahlen ausgibt, die durch ',' getrennt sind, z 1,2,3,4. Jetzt möchte ich diese Zahlen dem Skript s2als Argumente geben, damit s2 auf jedem von ihnen ausgeführt wird und das Ergebnis in einer separaten Zeile ausgibt. Wenn zum Beispiel s2 Zahlen mit zwei multipliziert, ist dies das Ergebnis, nach dem ich suche:

2
4
6
8

Was ich gerade mache ist:

s1 | xargs -d "," | xargs -n1 s2

Aber ich habe das Gefühl, dass ich es so dumm mache! Meine Frage lautet also:

Was ist der richtige Weg, um es zu tun?

Mein Problem mit meiner Lösung ist, dass es xargs zweimal aufruft und zweimal über die Eingabe iteriert, was für meine Augen natürlich aufgrund der Leistung nicht vernünftig ist! Die Antwort xargs -d "," -n1scheint nett zu sein, aber ich bin mir nicht sicher, ob sie nur einmal wiederholt wird. Wenn dies der Fall ist, überprüfen Sie dies bitte in Ihrer Antwort, und ich werde es akzeptieren. Übrigens würde ich Perl lieber nicht verwenden, da es immer noch zweimal iteriert und Perl auf vielen Systemen möglicherweise nicht vorhanden ist.


1
Wenn es funktioniert, warum nennst du es dumm? Wenn die Ausführungszeit wichtig ist, dann ist das eine andere Sache, die Sie hier lassen müssen
George Udosen,

2
Versuchen Sie diess1 | xargs -d "," -n1 s2
George Udosen

1
Ich vermute, dass ein Teil des Problems darin besteht, die Auswirkungen der Iteration falsch zu verstehen. Das Iterieren über die Elemente in so etwas wie einem assoziativen Array ist aufgrund der Kosten für das Durchlaufen dieser Datenstruktur schlecht, aber das "Iterieren" im Allgemeinen ist nicht von Natur aus schlecht. Insbesondere das zeilenweise Lesen von Daten in STDIN ist kein großes Leistungsproblem. Das Leistungsproblem hierbei sind eher die Kosten für das Laichen eines neuen Prozesses und das Einrichten der Pipeline. Solange Sie dies nicht häufig tun (wie in einer Schleife), ist die Sorge um die Leistung von xargs wahrscheinlich ein Beispiel für eine vorzeitige Optimierung.
Dannysauer

Antworten:


18

Dies sollte auch funktionieren:

s1 | xargs -d "," -n1 s2

Testfall:

printf 1,2,3,4 | xargs -d ',' -n1 echo

Ergebnis:

1
2
3
4

Wenn s1diese Liste gefolgt von einem Zeilenumbruchzeichen ausgegeben wird, möchten Sie sie entfernen, da sonst der letzte Aufruf 4\nstatt 4:

s1 | tr -d '\n' | xargs -d , -n1 s2

6

Wenn Sie s2mehrere Argumente akzeptieren können, können Sie Folgendes tun:

(IFS=,; ./s2 $(./s1))

Dies überschreibt IFS vorübergehend als Komma, alles in einer Unterschale, sodass s2die Ausgabe von s1durch Kommas getrennt wird. Die Unterschale ist eine Kurzform zum Ändern von IFS, ohne den vorherigen Wert zu speichern oder zurückzusetzen.

Eine frühere Version dieser Antwort war falsch, wahrscheinlich aufgrund einer verbleibenden IFS-Einstellung, die die Ergebnisse beschädigte. Vielen Dank an ilkkachu für den Hinweis auf meinen Fehler .

Um die Ausgänge manuell zu durchlaufen und einzeln bereitzustellen s2, wird hier das Speichern und Zurücksetzen von IFS demonstriert:

oIFS="$IFS"
IFS=,
for output in $(./s1); do ./s2 "$output"; done
IFS="$oIFS"

oder führen Sie die IFS-Bits wie zuvor in einer Subshell aus:

(
IFS=,
for output in $(./s1); do ./s2 "$output"; done
)

1
Bist du dir bei diesem ersten sicher? bash -c 'IFS=, printf "%s\n" $(echo 1,2,3)'druckt 1,2,3auf meinem System, dh es gibt keine Aufteilung.
Ilkkachu

Ich werde es in Kürze noch einmal testen, aber ich vermute ein anderes Verhalten basierend auf eingebauten und externen Programmen.
Jeff Schaller

das gleiche mit /usr/bin/printfund/bin/echo
ilkkachu

1
@ilkkachu Sie haben Recht, die Wortaufteilung erfolgt, bevor IFS neu zugewiesen wird. In diesem Fall (IFS=,; printf "%s\n" $(echo 1,2,3))sollte dies funktionieren.
Undercat applaudiert Monica

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.