2012-06-09 17 views
20

Quiero dirigir la salida de printf en una secuencia de comandos bash a stderr en lugar de stdout.¿Qué método debo usar para escribir mensajes de error en 'stderr' usando 'printf' en un script bash?

Soy no preguntar acerca de la redirección sea stderr o stdout desde donde quiera que se encaminan actualmente. Solo quiero poder enviar la salida de printf a stderr en lugar de a la predeterminada de stdout.

Experimenté un poco y descubrí que anexando 1>&2 al , como se muestra en el ejemplo siguiente, parece que hago lo que quiero. Sin embargo, tengo no experiencia usando bash. Entonces mi pregunta primaria es si hay una forma de "mejor" para hacer esto en bash?

Por "mejor" Quiero decir, ¿hay otra forma de hacer esto que sea más comúnmente utilizada, más convencional o más idiomática? ¿Cómo lo haría un programador de bash más experimentado?

#!/bin/bash 
printf "{%s} This should go to stderr.\n" "$(date)" 1>&2 
printf "[(%s)] This should go to stdout.\n" "$(date)" 

también tengo una pregunta secundaria. Lo estoy pidiendo no tanto porque yo necesito para saber, pero más porque solo tengo curiosidad y me gustaría tener una mejor comprensión de lo que está sucediendo.

Parece que lo anterior solo funcionará cuando se ejecute dentro de un script de shell. No parece funcionar cuando lo intento desde una línea de comando.

Aquí hay un ejemplo de lo que quiero decir.

[email protected]:~$ printf "{%s} Sent to stderr.\n" "$(date)" 1>&2 2> errors.txt 
{Sat Jun 9 14:08:46 EDT 2012} Sent to stderr. 
[email protected]:~$ ls -l errors.txt 
-rw-rw-r-- 1 irrational irrational 0 Jun 9 14:39 errors.txt 

Yo esperaría que el comando anterior printf no tener salida, ya que la salida debe ir a stderr, que a su vez debería ir a un archivo. Pero esto no sucede. ¿Huh?

Respuesta

22

En primer lugar, sí, 1>&2 es lo correcto.

En segundo lugar, la razón por la que su ejemplo 1>&2 2>errors.txt no funciona es debido a los detalles de qué es exactamente lo que hace la redirección.

1>&2 significa "make filehandle 1 punto donde sea que filehandle 2 lo haga actualmente" - es decir, las cosas que se habrían escrito en stdout ahora irán a stderr. 2>errors.txt significa "abrir un identificador de archivo a errors.txt y hacer que Filehandle 2 apunte a él" - es decir, las cosas que se habrían escrito en stderr ahora van a errors.txt.Pero Filehandle 1 no se ve afectado en absoluto, por lo que las cosas escritas en stdout siguen en stderr.

Lo que se debe hacer es 2>errors.txt 1>&2, lo que hará que las escrituras tanto stderr y stdout ir a errors.txt, debido a que la primera operación será "abierta errors.txt y hacer punto stderr a ella", y la segunda operación será "hacer stdout point a donde stderr apunta ahora ".

+0

Sí, de hecho, '2> errors.txt 1> & 2' es lo que debería haber intentado usar. Me siento tonto en retrospectiva, pero este parece ser uno de esos errores tontos que tengo que seguir haciendo hasta que la forma correcta de hacerlo se vuelva "obvia" para mí. ;-) Muchas gracias por la comprensión. –

6
  1. Eso me parece razonable. No es necesario el 1, sin embargo - que funcionará como es, pero está implícita:

    printf "{%s} This should go to stderr.\n" "$(date)" >&2 
    
  2. que tiene un problema de orden de operaciones:

    $ printf "{%s} Sent to stderr.\n" "$(date)" 2> errors.txt 1>&2 
    $ ls -l errors.txt 
    -rw-r--r-- 1 carl staff 47 Jun 9 11:51 errors.txt 
    $ cat errors.txt 
    {Sat Jun 9 11:51:48 PDT 2012} Sent to stderr. 
    
+0

+1. Consulte http://www.gnu.org/software/bash/manual/bashref.html#Redirections para obtener más información. –

+0

Mi impresión es que '1> & 2' es ligeramente menos ambiguo que simplemente'> & 2'. ¿No? (Con eso quiero decir, indica más claramente lo que le está sucediendo a una persona que mira el guión. Bash obviamente no le importa.) –

+0

Claro, está bien tenerlo, simplemente no lo necesita. –

1

Los modismos típicos son:

echo foo >&2   # you don't need to specify file descriptor 1 
echo foo > /dev/stderr # more explicit, but wordier and less portable 
2

La pregunta parece indicar cierta confusión. No desea redireccionar stdout, solo quiere que printf envíe su salida a stderr ... Pero para eso, debe usar la redirección.

El comando printf siempre envía salida normal a su salida estándar. Eso es lo que printf hace. Para lograr lo que desea, debe tener el shell arregle que stdout apunte temporalmente a donde quiera que vaya la salida. Tenga en cuenta que digo temporalmente. Cuando se escribe un comando como

$ printf "Hello World!" >&2 

la cáscara modifica el mango salida estándar para la duración de la ejecución de la sentencia printf. Luego, el shell restaura el valor original de stdout antes de continuar con el siguiente comando. De hecho, si desea redirigir la salida estándar de forma permanente, se utiliza el comando especial

$ exec >&2 

Después de la concha ha ejecutado esto, la cáscara ya no se acuerda del valor original de la manija de la salida estándar.

Cuestiones relacionadas