2012-01-31 14 views
15

Quiero capturar la salida de dos programas simultáneos (colas en archivos de registro) en una secuencia de salida en bash.Combinar la salida de dos programas simultáneos con bash

He utilizado este programa de ejemplo para la prueba:

function foo { for i in $(seq 1 10); do echo "program $*"; sleep 1; done } 

Ahora las siguientes obras excelentes

(foo bar & foo baz &) | tee /tmp/output 

pero una vez que agrego una tubería adicional en la mezcla ya no funciona:

(foo bar | grep bar & foo baz &) | tee /tmp/output # does't work 

La salida se vuelve secuencial. Podría hacer un programa separado que incluya el grep pero me gustaría saber si hay una forma de evitarlo.

Si alguien puede explicar por qué no funciona, estaría muy feliz.

Respuesta

7

¡Buena pregunta! Este me dejó perplejo un poco, pero creo que sé lo que está pasando. Lo que está sucediendo es que grep está almacenando en búfer la salida. Entonces, si lo dejas correr, verás que todo se inunda al final. Si le sucede a estar usando GNU grep tratar de pasar la opción --line-buffer:

(foo bar | grep --line-buffered bar & foo baz &) | tee /tmp/output 

aventurar una conjetura, y la mente que eso es esencialmente lo que es, yo diría que grep se almacena en búfer de salida más porque isatty(1) indicaría que es no escribiendo en un TTY (aunque está viendo la salida en un TTY a través de tee). Al almacenar más salida, realiza menos llamadas write(), y es más eficiente. El comportamiento familiar de ejecutar grep y ver la salida en un terminal está almacenado en línea: las líneas aparecen a medida que se encuentran. Esta opción fuerza grep para que se ejecute en ese modo.

Tenga en cuenta que, como advierte la página del manual, esto podría tener un impacto en el rendimiento de grep.

+0

"a pesar de que es, debido a la camiseta". grep está * no * escribiendo a un tty. grep está escribiendo en un tubo, y el tee está escribiendo en un tty. –

+0

Tienes toda la razón. Pobre redacción de mi parte: voy a editar mi publicación para aclararla. – FatalError

1

Debido al uso de la tubería entre foo bar y grep usted está haciendo grep que esperar a la salida del comando foo bar y por eso todas las líneas con bar vienen en seguida después de las líneas de Baz. Si realmente quieres a grep algo de la orden entonces definir otra función como esta:

function foo1 { for i in {1..3}; do echo "program $*" | grep "$*"; sleep 1; done } 

y luego ejecutar:

(foo1 bar & foo baz &) | tee /tmp/output 

Ahora se dará cuenta de que la producción se ve así:

program baz 
program bar 
program baz 
program bar 
program baz 
program bar 
... 
...