¿Cómo puedo unir dos tuberías con nombre en una sola secuencia de entrada en Linux?

64

Usando la función de tuberías ( |) en Linux, puedo reenviar la entrada estándar a una o varias secuencias de salida.

Puedo usar teepara dividir la salida para separar subprocesos.

¿Hay un comando para unir dos flujos de entrada?

¿Cómo voy a hacer esto? ¿Cómo funciona diff?

Cristian Ciupitu
fuente

Respuestas:

105

Personalmente, mi favorito (requiere bash y otras cosas que son estándar en la mayoría de las distribuciones de Linux)

Los detalles pueden depender mucho de lo que generan las dos cosas y de cómo desea fusionarlas ...

Contenido de command1 y command2 uno tras otro en la salida:

cat <(command1) <(command2) > outputfile

O si ambos comandos generan versiones alternativas de los mismos datos que desea ver uno al lado del otro (he usado esto con snmpwalk; números en un lado y nombres MIB en el otro):

paste <(command1) <(command2) > outputfile

O si desea comparar la salida de dos comandos similares (por ejemplo, encontrar en dos directorios diferentes)

diff <(command1) <(command2) > outputfile

O si son salidas ordenadas de algún tipo, combínelas:

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

O ejecute ambos comandos a la vez (aunque podría mezclar un poco las cosas):

cat <(command1 & command2) > outputfile

El operador <() configura una canalización con nombre (o / dev / fd) para cada comando, canaliza la salida de ese comando en la canalización con nombre (o / dev / fd filehandle reference) y pasa el nombre en la línea de comandos. Hay un equivalente con> (). Podría hacer: command0 | tee >(command1) >(command2) >(command3) | command4enviar simultáneamente la salida de un comando a otros 4 comandos, por ejemplo.

freiheit
fuente
¡increíble! He leído la página de manual de bash mucho tiempo, pero no la había elegido
Javier
2
Puede encontrar la referencia en la [guía avanzada de secuencias de comandos bash] ( tldp.org/LDP/abs/html/process-sub.html ) en el proyecto de documentación de linux
brice
3
yo era capaz de evitar que las líneas intercaladas canalizando a través grep --line-buffered- práctico para concurrentemente grep'ing la tailde varios archivos de registro. ver stackoverflow.com/questions/10443704/line-buffered-cat
RubyTuesdayDONO
16

Puede agregar dos vapores a otro con cat, como lo muestra el gorila.

También puede crear una FIFO, dirigir la salida de los comandos a eso, luego leer desde la FIFO con cualquier otro programa:

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

Particularmente útil para programas que solo escribirán o leerán un archivo, o para mezclar programas que solo emiten archivos / stdout con uno que solo admite el otro.

Chris S
fuente
2
Este funciona en pfSense (FreeBSD) mientras que la respuesta aceptada no. ¡Gracias!
Nathan
9
(tail -f /tmp/p1 & tail -f /tmp/p2 ) | cat > /tmp/output

/tmp/p1y /tmp/p2son sus tuberías de entrada, mientras que /tmp/outputes la salida.

gorila
fuente
66
Nota: A menos que ambos comandos en el lado ()ras su producción en cada línea (y algunas otras normas POSIX oscuros para la atomicidad), que podría terminar con algunos extraños luchando en la entrada al gato ...
Freiheit
¿No deberías usar punto y coma en lugar de un signo de carácter?
Samir
esto es algo épico
Mobigital
5

He creado un programa especial para esto: fdlinecombine

Lee varias tuberías (generalmente salidas de programa) y las escribe en stdout linealmente (también puede anular el separador)

Vi.
fuente
Funciona según lo anunciado. Gracias por hacerlo público.
alexei
3

Un comando realmente genial que he usado para esto es tpipeque tal vez necesites compilar porque no es tan común. Es realmente genial para hacer exactamente de lo que estás hablando, y es tan limpio que generalmente lo instalo. La página del manual se encuentra aquí http://linux.die.net/man/1/tpipe . La descarga actualmente listada se encuentra en este archivo http://www.eurogaran.com/downloads/tpipe/ .

Se usa así,

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

Ten cuidado aquí; solo atraparlos terminará mezclando los resultados de formas que quizás no desee: por ejemplo, si son archivos de registro, probablemente no quiera una línea insertada a la mitad de una línea desde la otra. Si eso está bien, entonces

tail -f / tmp / p1 / tmp / p2> / tmp / output

trabajará. Si eso no está bien, entonces tendrá que encontrar algo que haga el almacenamiento en línea y solo genere líneas completas. Syslog hace esto, pero no estoy seguro de qué más podría hacer.

EDITAR: optimización para lectura sin búfer y canalizaciones con nombre:

considerando / tmp / p1, / ​​tmp / p2, / tmp / p3 como canalizaciones con nombre, creado por "mkfifo / tmp / p N "

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

ahora de esta manera, podemos leer la salida llamada pipe "/ tmp / p3" sin buffer por:

cola -f / tmp / p3

hay un pequeño error de tipo, debe "inicializar" la primera tubería de entrada / tmp / p1 de la siguiente manera:

echo -n> / tmp / p1

para seguir , aceptará primero la entrada de la segunda tubería / tmp / p2 y no esperará hasta que algo llegue a / tmp / p1. este puede no ser el caso, si está seguro, el / tmp / p1 recibirá primero la entrada.

También se necesita la opción -q para que cola no imprima basura sobre nombres de archivos.

pjz
fuente
lo más útil será: "tail -q -f / tmp / p1 / tmp / p2 | another_command", ya que se hará línea por línea y con la opción -q no imprimirá ninguna otra basura
readyblue
para el uso de archivos sin búfer / canalización con nombre: tail -q -f /tmp/p1 /tmp/p2 | awk '{print $0 > "/tmp/p3"; close("/tmp/p3"); fflush();}' & ahora el / tmp / p3 puede incluso denominarse canalización y puede leerlo simplemente tail -f /tmp/p3todo esto NO ESTÁ SUJETADO = línea por línea, sin embargo, hay un pequeño error de clasificación. el primer archivo / canalización con nombre debe inicializarse primero para que la cola acepte la salida del segundo. así que tendrás que hacerlo echo -n > /tmp/p1y todo funcionará sin problemas.
readyblue
1

El mejor programa para hacer esto es lmerge. A diferencia de la respuesta de freihart, está orientada a líneas, por lo que la salida de los dos comandos no se golpeará entre sí. A diferencia de otras soluciones, fusiona bastante la entrada para que ningún comando pueda dominar la salida. Por ejemplo:

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

Da salida de:

foo
bar
foo
bar
Rian Hunter
fuente