Como unir dois pipes nomeados no fluxo de entrada único no linux

64

Usando o |recurso pipes ( ) no Linux, posso encadear a entrada padrão para um ou vários fluxos de saída.

Eu posso usar teepara dividir a saída para separar sub processos.

Existe um comando para unir dois fluxos de entrada?

Como eu iria fazer isso? Como o diff funciona?

Cristian Ciupitu
fonte

Respostas:

105

Pessoalmente, meu favorito (requer bash e outras coisas que são padrão na maioria das distribuições Linux)

Os detalhes podem depender muito do resultado das duas coisas e como você deseja mesclá-las ...

Conteúdo de command1 e command2 um após o outro na saída:

cat <(command1) <(command2) > outputfile

Ou se os dois comandos produzirem versões alternativas dos mesmos dados que você deseja ver lado a lado (eu usei isso com o snmpwalk; números de um lado e nomes MIB do outro):

paste <(command1) <(command2) > outputfile

Ou se você deseja comparar a saída de dois comandos semelhantes (digamos, encontrar em dois diretórios diferentes)

diff <(command1) <(command2) > outputfile

Ou, se houver algum tipo de saída ordenada, mescle-as:

sort -m <(command1) <(command2) > outputfile

Ou execute os dois comandos de uma só vez (no entanto, você pode embaralhar um pouco as coisas):

cat <(command1 & command2) > outputfile

O operador <() configura um pipe nomeado (ou / dev / fd) para cada comando, canalizando a saída desse comando no pipe nomeado (ou / dev / fd filehandle reference) e passa o nome na linha de comando. Existe um equivalente a> (). Você pode fazer: command0 | tee >(command1) >(command2) >(command3) | command4enviar simultaneamente a saída de um comando para 4 outros comandos, por exemplo.

freiheit
fonte
impressionante! i li lotes manpage da festança de tempo, mas não tinha escolher que um
Javier
2
Você pode encontrar a referência no [guia avançado de script do bash] ( tldp.org/LDP/abs/html/process-sub.html ) no projeto de documentação do linux
brice
3
eu era capaz de impedir linhas intercaladas através da canalização grep --line-buffered- útil para concomitantemente grepos tailvários arquivos de log. veja stackoverflow.com/questions/10443704/line-buffered-cat
RubyTuesdayDONO
16

Você pode anexar dois vapores a outro com cat, como mostra o gorila.

Você também pode criar um FIFO, direcionar a saída dos comandos para isso e ler o FIFO com qualquer outro programa:

mkfifo ~/my_fifo
command1 > ~/my_fifo &
command2 > ~/my_fifo &
command3 < ~/my_fifo

Particularmente útil para programas que gravam ou leem apenas um arquivo, ou misturam programas que produzem apenas stdout / file com um que suporta apenas o outro.

Chris S
fonte
2
Este funciona no pfSense (FreeBSD), enquanto a resposta aceita não. Obrigado!
1957 Nathan
9
(tail -f /tmp/p1 & tail -f /tmp/p2 ) | cat > /tmp/output

/tmp/p1e /tmp/p2são seus canais de entrada, enquanto /tmp/outputé a saída.

gorila
fonte
6
Nota: A menos que ambos os comandos ao lado ()liberem sua saída em todas as linhas (e algumas outras regras obscuras do POSIX para atomicidade), você pode acabar com uma estranha disputa na entrada para gerar ...
freiheit
Você não deve usar ponto-e-vírgula em vez do caractere e comercial?
Samir
isso é coisa épica
Mobigital
5

Eu criei um programa especial para isso: fdlinecombine

Ele lê vários pipes (geralmente saídas de programas) e os grava no stdout linewise (você também pode substituir o separador)

Vi.
fonte
Funciona como anunciado. Obrigado por torná-lo público.
Alexei
3

Um comando muito legal que usei para isso é que tpipevocê pode precisar compilar porque não é tão comum. É realmente ótimo para fazer exatamente do que você está falando, e é tão limpo que eu costumo instalá-lo. A página de manual está localizada aqui http://linux.die.net/man/1/tpipe . O download listado atualmente está neste arquivo http://www.eurogaran.com/downloads/tpipe/ .

É usado assim,

## Reinject sub-pipeline stdout into standard output:
$ pipeline1 | tpipe "pipeline2" | pipeline3
JM Becker
fonte
3

Tenha cuidado aqui; apenas colocá-los acabará misturando os resultados de maneiras que você não deseja: por exemplo, se forem arquivos de log, você provavelmente não quer uma linha de uma inserida no meio da linha e na outra. Se estiver tudo bem, então

tail -f / tmp / p1 / tmp / p2> / tmp / saída

vai funcionar. Se não estiver tudo bem, você terá que encontrar algo que faça buffer de linha e só produza linhas completas. O Syslog faz isso, mas não tenho certeza do que mais possa.

EDIT: otimização para leitura sem buffer e pipes nomeados:

considerando / tmp / p1, / ​​tmp / p2, / tmp / p3 como pipes nomeados, criados por "mkfifo / tmp / p N "

cauda -q -f / tmp / p1 / tmp / p2 | awk '{print $ 0> "/ tmp / p3"; fechar ("/ tmp / p3"); fflush ();} '&

Agora, dessa maneira, podemos ler o canal chamado Output "/ tmp / p3" sem buffer por:

cauda -f / tmp / p3

existe um pequeno bug do tipo, você precisa "inicializar" o primeiro canal de entrada / tmp / p1:

eco -n> / tmp / p1

para atender , aceitará a entrada do segundo pipe / tmp / p2 primeiro e não espere até que algo chegue a / tmp / p1. pode não ser o caso, se você tiver certeza, o / tmp / p1 receberá a entrada primeiro.

Além disso, a opção -q é necessária para que a cauda não imprima lixo sobre os nomes de arquivos.

pjz
fonte
mais útil será: "tail -q -f / tmp / p1 / tmp / p2 | another_command", pois isso será feito linha por linha e com a opção -q não imprimirá nenhum outro lixo
readyblue
para arquivo sem buffer / uso de pipe nomeado: tail -q -f /tmp/p1 /tmp/p2 | awk '{print $0 > "/tmp/p3"; close("/tmp/p3"); fflush();}' & agora o / tmp / p3 pode até ser nomeado pipe e você pode lê-lo simplesmente, tail -f /tmp/p3tudo isso é UNBUFFERED = linha por linha , no entanto, existe um pequeno erro de classificação. o primeiro arquivo / pipe nomeado precisa ser inicializado primeiro para que a cauda aceite a saída do segundo. então você precisará echo -n > /tmp/p1e do que tudo funcionará sem problemas.
readyblue
1

O melhor programa para fazer isso é lmerge. Diferentemente da resposta do freihart, ela é orientada a linhas, de modo que a saída dos dois comandos não se derruba. Ao contrário de outras soluções, ele mescla a entrada de maneira justa, de modo que nenhum comando possa dominar a saída. Por exemplo:

$ lmerge <(yes foo) <(yes bar) | head -n 4

Dá saída de:

foo
bar
foo
bar
Rian Hunter
fonte