Con bash, ¿cómo puedo canalizar el error estándar en otro proceso?

138

Es bien sabido cómo canalizar la salida estándar de un proceso en la entrada estándar de otro proceso:

proc1 | proc2

Pero, ¿qué sucede si quiero enviar el error estándar de proc1 a proc2 y dejar que la salida estándar vaya a su ubicación actual? Se podría pensar bashque tendría un comando en la línea de:

proc1 2| proc2

Pero, por desgracia, no. ¿Hay alguna forma de hacer esto?

paxdiablo
fuente
Puede hacer una redirección tan simple en rc, que es otro shell. Por ejemplo: proc1 |[2] proc2. ¿No es lindo? bashAunque no en .
Rolf

Respuestas:

169

También hay sustitución de procesos . Lo que hace que un proceso sustituya a un archivo.
Puede enviar stderra un archivo de la siguiente manera:

process1 2> file

Pero puede sustituir un proceso para el archivo de la siguiente manera:

process1 2> >(process2)

Aquí hay un ejemplo concreto que se envía stderrtanto a la pantalla como a un archivo de registro.

sh myscript 2> >(tee -a errlog)
escocés
fuente
23
Esto responde correctamente la pregunta planteada y debería ser la respuesta aceptada por @paxdiablo
mmlb
Intenté esto No funcionó ( weston --help 2> >(less)), y rompió mi caparazón, tuve que salir y volver a iniciar sesión.
Rolf
1
@Rolf si ambos weston --helpy lessesperan tener interacción con el teclado, pero solo 1 de ellos lo recibe, entonces puede estar en una situación incómoda. Intente hacer pruebas con algo como en su greplugar. Además, es posible que ambas entradas del mouse / teclado vayan al segundo comando de todos modos en lugar de a Weston.
BeowulfNode42
88

Puedes usar el siguiente truco para intercambiar stdout y stderr. Entonces solo usa la funcionalidad de tubería normal.

( proc1 3>&1 1>&2- 2>&3- ) | proc2

Siempre stdouty stderrambos señalaron la misma posición en la salida, esto le dará lo que necesita.

Lo que hace el x>ybit es cambiar el identificador de archivo xpara que ahora envíe su información a donde yapunta actualmente el identificador de archivo . Para nuestro caso específico:

  • 3>&1crea un nuevo identificador 3que saldrá al identificador actual1 (stdout original), solo para guardarlo en algún lugar para el último punto de viñeta a continuación.
  • 1>&2modifica el manejador 1(stdout) para enviarlo al manejador actual2 (stderr original).
  • 2>&3-modifica el manejador 2(stderr) para que salga al manejador actual3 (stdout original) y luego cierra el manejador 3(a través de -al final).

Es efectivamente el comando de intercambio que ves en los algoritmos de clasificación:

temp   = value1;
value1 = value2;
value2 = temp;
paxdiablo
fuente
3
¿Cuál es el valor de usar 1>&2-aquí en lugar de solo 1>&2? No entiendo por qué querríamos cerrar fd 2, si solo vamos a reabrirlo / reasignarlo de inmediato.
dubiousjim
1
@dubiousjim, no hay ventaja en ese caso particular, sospecho que lo hice solo para ser coherente: cerrar el controlador de archivos 3 es una buena idea para liberarlo.
paxdiablo
Buen punto, @ovgolovin, no puedo creer que nadie haya recogido eso en siete meses desde que hice esa edición. Solucionado según su sugerencia.
paxdiablo
tratando de hacer que gcc's make (que está coloreado en mi sistema) funcione con esto "(make 3> & 1 1> & 2- 2> & 3-) | less -R" while "(ls -al 3> & 1 1> & 2- 2> & 3-) | less -R "funciona como se esperaba.
no sincronizado
Parece que sus explicaciones están al revés para las segundas dos redirecciones. 1> y 2- establece el controlador de archivo 2 (stderr original) para manejar 1 (stdout original) 2> y 3- establece el controlador de archivo 3 (stdout copiado) para manejar 2 (stderr original). Por favor, corrígeme si me equivoco. por cierto, supongo que el guión en 2 es para evitar que se envíen nuevos datos stderr a este búfer mientras se rellenan con los datos de stdout.
aghsmith
70

Bash 4 tiene esta característica:

Si se usa '| &', el error estándar del comando1 se conecta a la entrada estándar del comando2 a través de la tubería; es la abreviatura de 2> & 1 |. Esta redirección implícita del error estándar se realiza después de cualquier redirección especificada por el comando.

zsh también tiene esta característica.

-

Con otros shells / antiguos, simplemente ingrese esto explícitamente como

FirstCommand 2> y 1 | OtroCommand

Pausado hasta nuevo aviso.
fuente
14
Al leer los documentos, eso produce tanto error estándar como salida en lugar de solo stderr, pero es bueno saberlo. Es hora de empezar a mirar bash 4, creo.
paxdiablo 02 de
El manual actual de bash dice "Si se usa | &, el error estándar del comando, además de su salida estándar, se conecta a la entrada estándar del comando2". Esto no es explícitamente lo que quiere el OP.
Peter - Restablece a Mónica el
@ PeterA.Schneider: El OP dice "deje la salida estándar yendo a su ubicación actual", lo cual puede ser ambiguo.
Pausado hasta nuevo aviso.
No veo ninguna ambigüedad. Su sugerencia (1) combina las dos corrientes. (2) OtherCommandescribe los datos combinados en alguna parte, posiblemente en otra parte. Por lo tanto, no son los mismos datos, y potencialmente van a otro lado. Eso es casi lo opuesto al deseo del OP, ¿no?
Peter - Restablece a Mónica el
@ PeterA.Schneider: ¿Dónde más está la ubicación actual de la salida estándar? Si proc1sale a stdout y stderr y quieres que stderr vaya al stdin de proc2(que es a donde va el stdout de proc1), entonces mi respuesta logra eso. Le di al OP lo que pidió , quizás no lo que quería pedir. Ahí radica la posible ambigüedad. El OP aceptó la respuesta que intercambia stdout y stderr que no es lo que pidió.
Pausado hasta nuevo aviso.
27

El intercambio es excelente ya que resuelve el problema. En caso de que ni siquiera necesite el stdout original, puede hacerlo de esta manera:

proc1 2>&1 1>/dev/null | proc2

El orden es vital; no querrías

proc1 >/dev/null 2>&1 | proc1

Como esto redirigirá todo a /dev/null!

kccqzy
fuente
0

Ninguno de estos realmente funcionó muy bien. La mejor manera que encontré de hacer lo que querías es:

(command < input > output) 2>&1 | less

Esto solo funciona en casos donde commandno necesita entrada de teclado. p.ej:

(gzip -d < file.gz > file) 2>&1 | less

pondría errores gzip en menos

Sbingner
fuente