Como eu passaria a saída de um comando para vários comandos?

20

Usando a substituição do processo ou agrupando e encanando, pode-se passar a saída ( stdout ) um conjunto de comandos como entrada para outro comando.

Exemplo:

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

Mas existe o oposto?

Ou seja, existe uma maneira de enviar a saída de um comando como entrada para muitos outros comandos em uma única linha ?

Algo como :

cat testfile | wc | tail -n 5

( Não use pipelines literalmente ). Aqui estou tentando passar a saída cat testfilepara ambos wcetail -n 5

Outro exemplo seria:

( para obter a última palavra de uma frase )

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

Respostas:

21

Resposta rápida. Você pode usar tee >(what_to_do) >(another_thing_to_do)para continuar com o seu comando para tantas coisas diferentes que você deseja fazer.

Exemplo:

Saída do arquivo de teste original:

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

Saída com teecomandos adicionados:

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

Cada comando no tee são apenas comandos normais que você usaria na linha de comando, como o add in >(head -1 | wc)funciona também.

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

Ou você também pode pegar a última palavra de dizer a última linha usando awkwith $NFcom um wcbem como este:

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

NOTA: A adição de um |comando de pipe ao final pode substituir usando os vários comandos dotee comando. Eu tenho alguns exemplos aqui que eu tenho testado:

Exemplo 1 (comando Pipe, puxando todas as últimas palavras):

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

Exemplo 2 (não mostra a saída dos comandos wc. Comando de pipe capturando a 3ª palavra.):

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

Exemplo 3 (Agarrando a 3ª palavra da linha de 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

Exemplo 4 (Agarrando a última palavra da linha de 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

Espero que isto ajude!

Terrance
fonte
3
Eu amo tee e café! '-)
Elder Geek
11
A declaração sobre a ordem da saída entre os vários consumidores de teeé falsa. O motivo pelo qual você normalmente obtém a ordem correta é que, em uma máquina de baixa carga, o primeiro processo do consumidor é executado primeiro. Em uma máquina mais movimentada, o primeiro consumidor pode dormir antes de imprimir qualquer coisa.
Matei David
@MateiDavid Não posso provar o contrário, então acabei de remover a declaração. Nada demais.
Terrance 4/10
2
Veja minha resposta. Mas, mais sério, teenão tem idéia dos consumidores - eles são criados por bashquem processa a linha. Tudo o que bashfaz é copiar os descritores de arquivos abertos. Além disso, você tem vários consumidores escrevendo para descritores de arquivos abertos no mesmo arquivo. O kernel cuida disso, mas certamente a ordem em que eles apareceram na bashlinha de comando não será um fator.
Matei David
17

Você precisa teedividir o fluxo em partes. Experimentar:

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

Notas:

  • Se vários processos ( wc, tail) estiverem gravando no stdout:

    • Você pode obter resultados ilegíveis.

    • Não há garantia sobre a ordem em que a saída será exibida. Para ver isso, tente sleep 1; wc -wcomo o segundo consumidor.

  • teebloqueará se algum de seus destinos não consumir o fluxo rápido o suficiente. Ou seja, os destinos serão alimentados na velocidade aproximadamente semelhante (módulo de buffer de tamanho fixo). Não há uma solução fácil para isso, a única alternativa é salvar o fluxo em um arquivo e alimentá-lo para os consumidores separadamente. Pois wce tailisso não é um problema.

Para a última palavra, é mais simples:

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

O moreutilspacote fornece o comando pee(mesclagem de pipe e tee, o que você achou?) Que faz exatamente isso.

Para o seu primeiro exemplo, você usaria:

cat testfile | pee wc "tail -n 5"

O segundo exemplo é mais complicado porque você deseja passar duas entradas para o último comando. Eu provavelmente usariaawk como as outras respostas.

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

T. Verron
fonte