Come passare l'output di un comando a più comandi?


20

Usando la sostituzione del processo o raggruppando & piping, si può passare all'output ( stdout ) un set di comandi come input per un altro comando.

Esempio :

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

Ma c'è il contrario?

Cioè, c'è un modo per inviare l'output di un comando come input per molti altri comandi in una sola riga ?

Qualcosa di simile a :

cat testfile | wc | tail -n 5

( Non prendere le condutture alla lettera ). Qui sto cercando di passare l'output di cat testfileentrambi wcetail -n 5

Un altro esempio potrebbe essere:

( per ottenere l'ultima parola di una frase )

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

Risposte:


21

Risposta rapida. Puoi usare tee >(what_to_do) >(another_thing_to_do)per continuare con il tuo comando per tutte le diverse cose che vuoi fare.

Esempio:

Output del file di test originale:

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

Uscita con teecomandi aggiunti:

:~$ 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

Ogni comando in tee è solo comandi normali che useresti sulla riga di comando, come funziona anche l'aggiunta >(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

Oppure si può anche afferrare l'ultima parola di dire l'ultima linea utilizzando awkcon $NFun wccosì come questo:

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

NOTA: l' aggiunta di un |comando pipe alla fine può sovrascrivere utilizzando i comandi multipli dal teecomando. Ho alcuni esempi qui che ho testato:

Esempio 1 (comando pipe che tira tutte le ultime parole):

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

Esempio 2 (Non mostra l'output dei comandi wc. Comando pipe che prende la terza parola.):

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

Esempio 3 (Afferrare la terza parola della riga dell'eco. Comando Tee):

:~$ 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

Esempio 4 (Afferrare l'ultima parola della riga dell'eco. Comando Tee):

:~$ 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

Spero che sia di aiuto!


3
Adoro tee e caffè! '-)
Elder Geek,

1
L'affermazione sull'ordinamento dell'output tra i vari consumatori di teeè falsa. Il motivo per cui di solito si ottiene l'ordine corretto è che su una macchina a basso carico, il primo processo consumer viene eseguito per primo. Su una macchina più occupata, il primo consumatore potrebbe essere messo a dormire prima di poter stampare qualsiasi cosa.
Matei David,

@MateiDavid Non posso provarlo altrimenti, quindi ho appena rimosso la dichiarazione. Nessun problema.
Terrance

2
Vedi la mia risposta Ma più seriamente, teenon ha idea dei consumatori, sono creati da bashchi elabora la linea. Tutto ciò che bashfa è copiare i descrittori di file aperti. Oltre a ciò, hai diversi utenti che scrivono su descrittori di file aperti sullo stesso file. Il kernel se ne occupa, ma sicuramente l'ordine in cui sono apparsi sulla bashriga di comando non sarà un fattore.
Matei David,

17

Devi teedividere il flusso in parti. Provare:

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

Gli appunti:

  • Se più processi ( wc, tail) stanno tutti scrivendo su stdout:

    • Potresti ottenere un risultato confuso.

    • Non vi è alcuna garanzia sull'ordine in cui apparirà il loro output. Per vedere questo, prova sleep 1; wc -wcome secondo consumatore.

  • teesi bloccherà se una delle sue destinazioni non consuma lo stream abbastanza velocemente. In altre parole, le destinazioni verranno immesse in input a una velocità approssimativamente simile (modulo buffer di dimensioni fisse). Non esiste una soluzione semplice per questo, l'unica alternativa è salvare il flusso in un file e inviarlo separatamente ai consumatori. Per wce tailquesto non è un problema.

Per l'ultima parola, è più semplice fare:

echo "some random words" | awk '{print $NF}'

5

Il moreutilspacchetto fornisce il comando pee(unione di pipe e tee, cosa hai pensato?) Che fa esattamente questo.

Per il tuo primo esempio, useresti:

cat testfile | pee wc "tail -n 5"

Il secondo esempio è più complicato perché si desidera passare due input all'ultimo comando. Probabilmente userei awkcome le altre risposte.

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.