¿Por qué '>' no redirige los mensajes de error de gcc?

9

Almacené el siguiente programa en new.c

int main() 
{ 
    a;
    return 0; 
}

Devuelve un mensaje de error. Quiero enviar este mensaje a un archivo. Entonces usé el siguiente comando

gcc new.c > temp.txt

Pero aún estaba obteniendo la salida en la terminal. Estoy usando Ubuntu 13.04. ¿Cómo puedo hacer que funcione?

Alex
fuente
Para referencia, vea también ¿Cuáles son los operadores de control y redirección de shell?
G-Man dice 'Restablece a Monica'

Respuestas:

16

Cuando compila un programa con gcc, hay diferentes tipos de salida: a stdouty stderr. Normalmente, el flujo >directo se dirigirá stdouta un archivo (por ejemplo, printf("hello world\n");se envía el resultado de a stdout). Sin embargo, el stderrmensaje continúa siendo enviado a la pantalla, ya que se supone que es "algo excepcional de lo que necesita que se le informe".

Hay una manera de redirigir stderr a un archivo: puede hacerlo con el siguiente comando (no muy intuitivo):

gcc new.c &> myFile

donde &>es "bash shorthand" para "redirigir todo". Como lo señaló @CharlesDuffy, el formulario compatible con POSIX es

gcc new.c > myFile 2>&1

Esto significa "compilar 'new.c' y enviar stdouta myFile. Y enviar stderr(2) al mismo lugar que stdout( &1=" el mismo lugar que stdout ").

Encontrará más detalles sobre diferentes redirecciones en http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-3.html y http://mywiki.wooledge.org/BashFAQ/055

Por cierto, si desea enviar algo desde su programa específicamente a stderr, puede hacerlo con lo siguiente

fprintf(stderr, "hello world - this is urgent.\n");

Si incluye eso en un programa, ejecute el programa y envíe la salida "normal" a un archivo, esto seguirá apareciendo en la consola. Entonces, si compila lo anterior en el ejecutable urgent, escriba

./urgent > /dev/null

en la consola, su salida aparecerá en la pantalla.

Floris
fuente
2
mywiki.wooledge.org/BashFAQ/055 es probablemente una mejor introducción a la redirección. Además, uno realmente debería presentar el formulario compatible con POSIX ( >myFile 2>&1), así como la extensión bash ( &>).
Charles Duffy
@CharlesDuffy: ambos muy buenos puntos. Los incluiré en mi respuesta para completar.
Floris
11

Debido a que >solo redirecciona stdout y se escriben los errores stderr, debe utilizar uno de los siguientes:

gcc new.c &> temp.txt ## redirect both stdout and stderr using bash or zsh only

...o...

gcc new.c >temp.txt 2>&1 ## redirect both stdout and stderr in any POSIX shell

&>es una extensión BASH que redirige a ambos stdouty stderra un archivo; de lo contrario, el enfoque más sencillo es la primera salida estándar de redirección ( >temp.txt), y luego hacer stderr (FD 2) una copia del identificador de archivo redirigido ya-en stdout (FD 1), así: 2>&1.

nims
fuente
4

Como han dicho los demás, Linux proporciona dos flujos de salida diferentes:

stdout o "salida estándar" es donde va toda la salida regular.
              Puede referenciarlo utilizando el descriptor de archivo 1.

stderr , o "error estándar" es una secuencia separada para información fuera de banda.
              Puede referenciarlo utilizando el descriptor de archivo 2.

¿Por qué dos flujos de salida diferentes? Considere una tubería de comandos imaginarios:

 decrypt $MY_FILE | grep "secret" | sort > secrets.txt

Ahora imagine que el decryptcomando falla y genera un mensaje de error. Si enviara ese mensaje stdout, lo enviaría a la tubería y, a menos que tuviera la palabra "secreto", nunca lo vería. Así que terminarías con un archivo de salida vacío, sin tener idea de lo que salió mal.

Sin embargo, dado que la tubería solo captura stdout, el decryptcomando puede enviar sus errores a stderrdonde se mostrarán en la consola.

Puede redirigir stdouty stderr, juntos o de forma independiente:

# Send errors to "errors.txt" and output to "secrets.txt"
# The following two lines are equivalent, as ">" means "1>"
decrypt $MY_FILE 2> errors.txt > secrets.txt
decrypt $MY_FILE 2> errors.txt 1> secrets.txt

Puede redirigir los errores stdouty procesarlos como si fueran resultados normales:

# The operation "2>&1" means "redirect file descriptor 2 to file
# descriptor 1. So this sends all output from stderr to stdout.
# Note that the order of redirection is important.
decrypt $MY_FILE > errors.txt 2>&1 

# This may be confusing.  It will store the normal output in a file
# and send error messages to stdout, where they'll be captured by 
# the pipe and then sorted.
decrypt $MY_FILE 2>&1 > output.txt | sort

También puede utilizar una notación "abreviada" para redirigir tanto stdout y stderr al mismo archivo:

decrypt $MY_FILE &> output.txt

Y, finalmente, el >operador primero truncará su archivo de salida antes de escribir en él. Si, en cambio, desea agregar datos a un archivo existente, use el >>operador:

decrypt $MY_FILE 2>> more_errors.txt >> more_secrets.txt
decrypt $MY_FILE >> more_output.txt 2>&1
Adam Liss
fuente
1
Dos objeciones: (1) El uso de expansiones de parámetros sin comillas ( $FOO) es una fuente común de errores, y demostrarlo en ejemplos no es tan bueno. (2) El uso de nombres de variables en mayúsculas es la razón principal de los conflictos de espacio de nombres entre el entorno y las variables integradas (mayúsculas por convención) y las variables locales (minúsculas por convención). (3) Alentar a las personas a usarlo repetidamente >>(que vuelve a abrir el archivo cada vez que se usa en un comando) en lugar de abrir un archivo una vez y dejar el descriptor de archivo abierto para que lo usen múltiples comandos da como resultado un código ineficiente.
Charles Duffy
... en el último punto, comparar a: exec 4>secrets; echo "this is a secret" >&4; echo "this is another secret" >&4
Charles Duffy
+1 Gracias por mantenerme honesto, @CharlesDuffy. Todos los buenos puntos. Omití intencionalmente execpor simplicidad, aunque en la práctica generalmente es una mejor estrategia.
Además, se puede contraer en o (donde debe haber espacios antes y después del , y a antes del ). command₁ > output_file ; command₂ >> the_same_output_file( command₁ ; command₂ )  > output_file{ command₁ ; command₂ ;  }  > output_file{;}
G-Man dice 'Restablecer a Monica'