Cómo canalizar stderr sin stdout de tubería


24

¿Cómo canalizo el flujo de error estándar sin canalizar el flujo de salida estándar?

Sé que este comando funciona, pero también escribe el estándar.

Command 2>&1 | tee -a $LOG

¿Cómo obtengo solo el error estándar?

Nota: Lo que quiero sacar de esto es simplemente escribir la secuencia stderr en un registro y escribir tanto stderr como stdout en la consola.

Respuestas:


26

Para hacer eso, use un descriptor de archivo adicional para cambiar stderr y stdout:

find /var/log 3>&1 1>&2 2>&3 | tee foo.file

Básicamente, funciona, o al menos creo que funciona, de la siguiente manera: las
redirecciones se evalúan de izquierda a derecha.

3>&1 Hace un nuevo descriptor de archivo, 3 un duplicado (copia) de fd 1 (stdout).

1>&2 Hacer stdout (1) un duplicado de fd 2 (stderr)

2>&3 Haga fd 2, un duplicado (copia) de 3, que anteriormente se hizo una copia de stdout.

Entonces ahora se cambian stderr y stdout.

| tee foo.file tee duplica el descriptor de archivo 1 que se convirtió en stderr.


Oh, no probado con ksh, aunque funciona con bash ...
Kyle Brandt

Gracias, funciona en ksh también. Creo que la mayoría de las cosas de tubería y flujo son estándar posix.
C. Ross

"Copiar" no es realmente correcto - Ver la respuesta de @ Guasqueño.
Kyle Brandt

Esto también funciona en Windows con tee.exeinstalado :)
Acorn

13

El comando Unix / Linux de Kyle hace el trabajo de cambiar el STDERR con el STDOUT; Sin embargo, la explicación no es del todo correcta. Los operadores de redireccionamiento no copian ni duplican, simplemente redirigen el flujo a una dirección diferente.

Reescribir el comando de Kyle moviendo temporalmente el 3> & 1 hasta el final, facilitaría la comprensión del concepto:

find /var/log  1>&2  2>&3  3>&1  

Sin embargo, escrito de esta manera, Linux mostraría un error porque & 3 aún no existe, ya que se encuentra antes de 3> & 1. 3> algo es una forma de declarar (definir) que vamos a usar una tercera tubería, por lo que debe ubicarse antes de que fluya agua en esa tubería, por ejemplo, la forma en que Kyle lo escribió. Pruebe esto de otra manera solo por diversión:

((echo "STD1";  anyerror "bbbb"; echo "STD2" ) 3>&1 4>&2 1>&4 2>&3) > newSTDOUT 2> newSTDERR

No tener una forma de hacer copias es una pena. No puede hacer cosas como "3> & 1 3> & 2" en el mismo comando, porque Linux solo usará el primero encontrado y descartará el segundo.

No he encontrado (todavía) una forma de enviar tanto el error como la salida regular a un archivo y también enviar una copia del error a la salida estándar con un comando. Por ejemplo, tengo un trabajo cron que quiero que ambas salidas (error y estándar) vayan a un archivo de registro y dejen que el error también salga para hacer un mensaje de correo electrónico enviado a mi BlackBerry. Puedo hacerlo con dos comandos usando "tee" pero el error no se muestra en el orden correcto entre la línea de salida regular en el archivo. Esta es la forma fea en que resolví el problema:

((echo "STD1"; sdfr "bbbb"; echo "STD2" ) 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1

Tenga en cuenta que tengo que usar log1 dos veces y tengo que agregar en ambos casos, el primero usando la opción "-a" para el comando "tee" y el segundo usando ">>".

Al hacer un gato log1 obtienes lo siguiente:

STD1
STD2
-bash: sdfr: command not found

Observe que el error no se muestra en la segunda línea como debería.


Corrección impresionante !
Kyle Brandt

Consulte zsh y la mult_iosopción ( activada de manera predeterminada) para poder redirigir un FD varias veces.
Tom Hale

2

de acuerdo con la página de manual de ksh (pdksh), puede hacer lo siguiente:

Comando 2> & 1> / dev / null | gato -n

es decir, dup stderr a stdout, redirigir stdout a / dev / null, luego canalizar a 'cat -n'

funciona en pdksh en mi sistema:

$ errorecho () {echo "$ @"> & 2;}

$ errorecho foo
foo

$ errorecho foo> / dev / null # aún debería mostrarse incluso con stdout redirigido
foo

$ errorecho foo 2> & 1> / dev / null | gato -n
     1 foo
PS   

También funciona con BusyBox
Udo G

1

Lo ejecuté como siempre quisiste, ya que también lo necesitaba y refiné tu comando. ahora para mí funciona correctamente usando bash 3.2 en debian squeeze usando esto

(echo "foo" 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1 >> log2

mientras que log1 registra stdout y stderr y log2 solo registra stderr y nada más lo pone en pantalla.

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.