Wie würde ich die Ausgabe eines Befehls an mehrere Befehle übergeben?

20

Durch Ersetzen von Prozessen oder durch Gruppieren und Weiterleiten kann die Ausgabe ( stdout ) einer Reihe von Befehlen als Eingabe für einen anderen Befehl übergeben werden.

Beispiel

wc < <(echo hi;echo bye)
(echo hi; bye) | wc

Aber gibt es das Gegenteil?

Gibt es eine Möglichkeit, die Ausgabe eines Befehls als Eingabe für viele andere Befehle in einer einzigen Zeile zu senden ?

So etwas wie :

cat testfile | wc | tail -n 5

( Nehmen Sie keine Pipelines wörtlich ). Hier versuche ich, die Ausgabe von cat testfilean beide wcund weiterzugebentail -n 5

Ein anderes Beispiel wäre:

( um das letzte Wort eines Satzes zu bekommen )

echo "some random words"| wc -c | cut -f(out put of wc -c) (output of first echo)
Severus Tux
quelle

Antworten:

21

Schnelle Antwort. Mit können Sie tee >(what_to_do) >(another_thing_to_do)Ihren Befehl für so viele verschiedene Aufgaben ausführen, wie Sie möchten.

Beispiel:

Originalausgabe der Testdatei:

:~$ cat testfile.txt 
Device Model:     LITEONIT LCS-256M6S 2.5 7mm 256GB
Serial Number:    TW0XFJWX550854187616

Ausgabe mit teehinzugefügten Befehlen:

:~$ cat testfile.txt | tee >(tail -1) >(wc) >(awk '{print $3,$1,$2}')
Device Model:     LITEONIT LCS-256M6S 2.5 7mm 256GB
Serial Number:    TW0XFJWX550854187616
LITEONIT Device Model:
TW0XFJWX550854187616 Serial Number:
      2      10      91
Serial Number:    TW0XFJWX550854187616

Jeder Befehl in tee ist nur ein normaler Befehl, den Sie in der Befehlszeile verwenden würden >(head -1 | wc).

:~$ cat testfile.txt | tee >(tail -1) >(head -1 | wc)  >(awk '{print $3,$1,$2}')
Device Model:     LITEONIT LCS-256M6S 2.5 7mm 256GB
Serial Number:    TW0XFJWX550854187616
      1       7      52
LITEONIT Device Model:
TW0XFJWX550854187616 Serial Number:
Serial Number:    TW0XFJWX550854187616

Oder Sie können auch greifen das letzte Wort in der letzten Zeile sagen von unter Verwendung von awkmit $NFmit einem wcauch wie folgt aus :

:~$ cat testfile.txt | tail -1 | tee >(wc) >(awk '{print $NF}')
Serial Number:    TW0XFJWX550854187616
TW0XFJWX550854187616
      1       3      39

ANMERKUNG: Das Hinzufügen eines |Pipe-Befehls am Ende kann die Verwendung mehrerer Befehle aus dem teeBefehl außer Kraft setzen . Ich habe hier einige Beispiele, die ich getestet habe:

Beispiel 1 (Pipe-Befehl, der alle letzten Wörter zieht):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) | awk '{print $NF}'
words
24
5
1

Beispiel 2 (Zeigt die Ausgabe der wc-Befehle nicht an. Pipe-Befehl greift nach dem 3. Wort.):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) | awk '{print $3}'
just

Beispiel 3 (Ergreifen des 3. Wortes der Echozeile. Tee-Befehl.):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) >(awk '{print $3}')
This is just five words
just
24
5
1

Beispiel 4 (Ergreifen des letzten Wortes der Echozeile. Tee-Befehl.):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) >(awk '{print $NF}')
This is just five words
words
24
5
1

Hoffe das hilft!

Terrance
quelle
3
Ich liebe Tee und Kaffee! '-)
Elder Geek
1
Die Aussage über die Reihenfolge der Ausgabe zwischen den verschiedenen Verbrauchern von teeist falsch. Der Grund, warum Sie normalerweise die richtige Reihenfolge erhalten, ist, dass auf einer Niedriglastmaschine der erste Verbraucherprozess zuerst ausgeführt wird. Auf einem geschäftigeren Computer wird der erste Verbraucher möglicherweise in den Ruhezustand versetzt, bevor er etwas drucken kann.
Matei David
@MateiDavid Ich kann es nicht anders beweisen, also habe ich gerade die Anweisung entfernt. Kein Problem.
Terrance
2
Siehe meine Antwort. Aber im Ernst, teehat keine Ahnung von den Verbrauchern - sie werden von bashdenen erstellt , die die Leitung bearbeiten. Sie bashmüssen lediglich die geöffneten Dateideskriptoren kopieren. Darüber hinaus haben Sie mehrere Konsumenten, die in Dateideskriptoren schreiben, die in derselben Datei geöffnet sind. Der Kernel kümmert sich darum, aber die Reihenfolge, in der sie in der bashBefehlszeile angezeigt werden , spielt sicherlich keine Rolle.
Matei David
17

Sie müssen teeden Stream in Teile teilen. Versuchen:

cat testfile | tee >(wc -l) >(wc -w) >(wc -c) | tail -n 5

Anmerkungen:

  • Wenn mehrere Prozesse ( wc, tail) in stdout schreiben:

    • Möglicherweise wird die Ausgabe verstümmelt.

    • Es gibt keine Garantie für die Reihenfolge, in der die Ausgabe erfolgt. Versuchen Sie sleep 1; wc -wals den zweiten Verbraucher , um das anzuzeigen.

  • teewird blockiert, wenn eines seiner Ziele den Stream nicht schnell genug verbraucht. Das heißt, die Ziele werden mit ungefähr gleicher Geschwindigkeit eingegeben (Modulo der Pufferung mit fester Größe). Es gibt keine einfache Lösung dafür. Die einzige Alternative besteht darin, den Stream in einer Datei zu speichern und ihn separat an die Konsumenten weiterzuleiten. Denn wcund taildas ist kein Thema.

Für das letzte Wort ist es einfacher:

echo "some random words" | awk '{print $NF}'
Matei David
quelle
5

Das moreutilsPaket enthält den Befehl pee(Zusammenführen von Pipe und Tee, was denkst du?), Der genau das tut.

Für Ihr erstes Beispiel verwenden Sie:

cat testfile | pee wc "tail -n 5"

Das zweite Beispiel ist komplizierter, da Sie zwei Eingaben an den letzten Befehl übergeben möchten. Ich würde wahrscheinlich awkdie anderen Antworten verwenden.

Link: https://joeyh.name/code/moreutils/

T. Verron
quelle