combinar la salida de dos comandos en bash


81

¿Es posible combinar la salida de estos dos comandos?

node ~/projects/trunk/index.js 
python ~/projects/trunk/run.py run

Ninguno de los comandos sale, así que no estoy seguro de cómo hacer esto.


3
Si los programas no terminan, ¿presumiblemente escriben salida continuamente? ¿Qué quieres hacer con su salida? Líneas intercaladas, ...? ¿Por qué quieres hacer esto?
vonbrand

2
El comando de nodo no genera mucho, pero aún necesita ejecutarse. Python one genera todas las solicitudes, quiero capturar ambas y verlas en la misma ventana de shell.
chovy

Respuestas:


108

Puede combinar dos comandos agrupándolos con { }:

{ command1 & command2; }

hasta ahora, puede redirigir el grupo a un archivo (el último ;antes }es obligatorio):

{ command1 & command2; } > new_file

si quieres separar STDOUTy STDERRen dos archivos:

{ command1 & command2; } > STDOUT_file 2> STDERR_file

3
No importa que sus programas no terminen. 'tail -f' tampoco "finaliza", pero aún funciona y combina las salidas de ambos programas. Funciona para más de dos comandos también. ^ c para salir mata solo uno de los comandos agrupados. Sin embargo, tendrás que matar a los demás manualmente.
SuperMagic

55
Parece que te falta el último ;antes }, ¡es obligatorio!
Gilles Quenot

2
Tenga cuidado: ¡esto no conserva líneas enteras! Obtendrá resultados poco confiables a medida que las líneas se dividen en parte y se mezclan entre sí. Puede probar esto con lo { yes {1..20} & yes {1..20}; } | grep -v '^1 2 3'que idealmente no imprimirá nada si las líneas no se rompen.
antak

8
Prefiero usar en &&lugar de &! command1 & command2- esto ejecuta el comando1 en segundo plano y el comando2 inmediatamente, ejecutando ambos comandos en paralelo y desordenando la salida. command1 && command2- esto ejecuta command1 (en primer plano) y luego, si command1 se ejecuta correctamente, ejecuta command2.
DUzun

1
@DUzun OP dijo que ninguno de los comandos sale, así que con su solución, el segundo comando nunca se ejecutará
Zoey Hewll

50

En términos más generales, es posible usar una agrupación de comandos o una subshell y redirigir la salida de todo el grupo a la vez.

Código:

( command1 ; command2 ; command3 ) | cat

{ command1 ; command2 ; command3 ; } > outfile.txt

La principal diferencia entre los dos es que el primero se divide en un proceso secundario, mientras que el segundo opera en el contexto del shell principal. Esto puede tener consecuencias con respecto a la configuración y el uso de variables y otras configuraciones de entorno, así como el rendimiento.

No olvide que el corchete de cierre en la agrupación de comandos (y funciones) debe estar separado del contenido por un punto y coma o una nueva línea. Esto se debe a "}"que en realidad es un comando (palabra clave) propio y debe tratarse como tal.


2
Redirección de ( )trabajos bien también.
muru

2
}No es un comando en absoluto. Es una palabra reservada. Lo mismo vale para {. Por lo general escribo estas listas, así: { command1;command2;} > outfile.txt. Puede agregar espacios después del punto y coma, pero no es necesario. Sin embargo, el espacio posterior { es necesario.
Comodín

1
Tenga cuidado: ¡esto no conserva líneas enteras! Obtendrá resultados poco confiables a medida que las líneas se dividen en parte y se mezclan entre sí. Puede probar esto con lo ( yes {1..20} & yes {1..20}; ) | grep -v '^1 2 3'que idealmente no imprimirá nada si las líneas no se rompen. (H / t a @antak).
Ole Tange

3
A veces, desea ejecutar el comando2 solo si el comando1 tuvo éxito:( command1 && command2 && command3 ) | cat
DUzun

Prefiero los corchetes ()como con los corchetes que {}se ejecuta como un progreso de fondo y luego tienes que lidiar con la salida de eso. También pipa al gato `| cat` es una mejor alternativa que `> / dev / stdout`
DarkMukke

2

Terminé haciendo esto, las otras sugerencias no funcionaron, ya que el segundo comando fue asesinado o nunca ejecutado.

alias app () {
    nohup python ~/projects/trunk/run.py run 1>/tmp/log 2>&1 &
    echo $! > /tmp/api.pid
    nohup node ~/projects/trunk/index.js 1>/tmp/log 2>&1 &
    echo $! > /tmp/client.pid
    tail -f /tmp/log
}

1
Nota: esto puede causar errores de E / S si los dos procesos intentan escribir en el archivo "al mismo tiempo".
Djizeus

2
puede especificar 2 archivos de registro diferentes y hacerlo, tail -f *.logaunque nunca he visto esto como un problema con 2 procesos diferentes que escriben en el mismo archivo de registro.
chovy

@chovy: ¿podrías escribir tu problema como pregunta aquí ... es útil?
Abdennour TOUMI

1
Tenga cuidado: ¡esto no conserva líneas enteras! Obtendrá resultados poco confiables a medida que las líneas se dividen en parte y se mezclan entre sí. Puede probar esto con command1 = yes {1..20}command2 = yes {1..20}y canalizar la salida combinada a través de la | grep -v '^1 2 3'cual idealmente no se imprimirá nada si las líneas no se rompen. (H / t a @antak).
Ole Tange

Además de eso, su disco puede funcionar lleno si la cantidad de datos es grande.
Ole Tange

2

Prueba esto:

paste $(node ~/projects/trunk/index.js) $(python ~/projects/trunk/run.py run) > outputfile

1
¿Qué hace 'pegar'?
chovy

@chovy, mira aquí: techrepublic.com/article/… Sin embargo, no estoy seguro de si funcionará en este contexto.
FixMaker

No creo que pegar sea apropiado aquí, ya que está destinado a poner columnas una al lado de la otra
Bernhard

@Bernhard de hecho. Pero no se especificó en los
requisitos

@ frogstarr78 Creo que es muy poco probable que esto sea lo que él quiere, pero tienes razón, no está especificado.
Bernhard

1

La mayoría de las soluciones hasta ahora tratan mal el problema de la línea parcial. Suponga por un segundo que los programas son:

cmd1() {
    perl -e 'while(1) { print "a"x3000_000,"\n"}'
}
export -f cmd1
cmd2() {
    perl -e 'while(1) { print "b"x3000_000,"\n"}'
}
export -f cmd2

Al ejecutarlos en paralelo, desea que la salida tenga líneas completas de as seguidas de líneas completas de bs. Lo que no desea es que asys se bmezclen en la misma línea ( tr -s abreemplaza la repetición de as con una sola a, por lo que es más fácil ver qué sucede):

# This is bad - half lines are mixed
$ (cmd1 & cmd2 ) | tr -s ab
bababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababa
ababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababab

Si en su lugar usa GNU Parallel, obtendrá líneas completas limpias con as o bs pero nunca mezcladas:

$ parallel --line-buffer ::: cmd1 cmd2 | tr -s ab
a
a
b
b
b
b
a

Las versiones más nuevas de GNU Parallel incluso evitan llenar su disco: lo anterior puede ejecutarse para siempre.


0

Como ya está usando node, es posible que desee probar simultáneamente

Ejecute múltiples comandos al mismo tiempo. Como npm run watch-js & npm run watch-lesspero mejor.


0

Para el caso especial de combinar múltiples salidas de comandos BASH en una línea, aquí hay una receta para ejecutar cada comando a su vez, eliminando cualquier nueva línea entre sus salidas.

(echo 'ab' && echo 'cd' && echo 'ef') | tr -d '\n'
>>> abcdef

Como ejemplo del mundo real, el siguiente código incrustará un mensaje ASCII entre dos cadenas fijas de bytes (formando un comando de impresión, en este caso)

#   hex prefix           encode a message as hex    hex suffix    | strip newline | hex to binary | (then, for example, send the binary over a TCP connection)
(echo '1b40' && echo "Test print #1" | xxd -p && echo '1d564103') | tr -d '\n'    | xxd -r -p     | nc -N 192.168.192.168 9100

(Nota: este método solo funciona si los comandos salen. Para combinar stdout de comandos que no salen, vea otras respuestas).


(1) Muestre la salida (esperada) de su segundo comando. (2) Muestre cómo el OP usaría esta técnica para resolver su problema.
Scott

1) El resultado del segundo comando es binario no ascii, por lo que no sería útil mostrarlo. 2) OP probablemente resolvió su problema específico entre 2013 y ahora. Esta pregunta ahora es efectivamente una referencia sobre la combinación de stdout de múltiples comandos Bash, por lo que creo que una técnica para combinarlos en una línea es una "receta" útil para mencionar aquí (ya que vine a buscarla y no pude encontrarla). eso).
Lucas
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.