2009-02-01 9 views
8

He codificado un programa en C que envía mensajes a la salida estándar utilizando printf y tengo problemas para redirigir la salida a un archivo (desde bash).Problema al redireccionar una salida del programa C en bash

que he probado:

./program argument >> program.out 
./program argument > program.out 
./program >> program.out argument 
./program > program.out argument 

En cada caso, se crea el archivo de program.out pero permanece vacío. Después de que termine la ejecución del tamaño del archivo es 0.

Si Omito la redirección al ejecutar el programa:

./program argument 

A continuación, todos los mensajes enviados a la salida estándar utilizando printf se muestran en la terminal.

Tengo otros programas C para los cuales no tengo problemas para redirigir la salida de esta manera. ¿Tiene que ver con el programa en sí? con el argumento pasando? ¿Dónde debería buscarse el problema?

Algunos detalles sobre el programa C:

  • No lee cualquier cosa, desde la entrada estándar
  • Se utiliza sockets BSD de Dominio de Internet
  • Se utiliza hilos POSIX
  • Se asigna una función especial controlador para Señal SIGINT con sigaction
  • Envía muchas líneas nuevas a stdout (para aquellos de ustedes que piensen que debo enjuagar)

Algunos código:

int main(int argc, char** argv) 
{ 
    printf("Execution started\n"); 
    do 
    {   
     /* lots of printf here */ 
    } while (1); 
    /* Code never reached */ 
    pthread_exit(EXIT_SUCCESS); 
} 
+0

¿Lo mismo programa sin redirección de la salida produce ninguna salida a la pantalla? – womble

+0

He editado la pregunta para aclarar eso. Gracias – mmutilva

Respuesta

14

Flushing después de saltos de línea sólo funciona al imprimir en una terminal, pero no necesariamente cuando se imprime en un archivo. Una búsqueda rápida en Google reveló esta página con más información: http://www.pixelbeat.org/programming/stdio_buffering/

Consulte la sección titulada "Modos de almacenamiento en búfer predeterminado".

Es posible que deba agregar algunas llamadas a fflush (stdout), después de todo.

También puede establecer el tamaño y el comportamiento del búfer usando setvbuf.

+1

¿Qué pasa cuando termina el programa? ¿No debería automáticamente stdout ser enjuagado automáticamente? – mmutilva

+0

¿Algún enlace con información sobre este comportamiento diferente del almacenamiento en memoria intermedia estándar entre enviarlo al terminal y a un archivo? – mmutilva

+0

He editado un enlace en mi respuesta, para que sea más fácil de ver para todos. En lugar de enjuagar explícitamente de vez en cuando, también puede cambiar el comportamiento del almacenamiento en búfer usando setvbuf (también vinculado en mi respuesta). – gclj5

3

¿Se ha terminado el programa cuando se verifica el contenido del archivo redirigido? Si aún se está ejecutando, es posible que su salida se mantenga almacenada temporalmente en algún lugar de la cadena, para que no la vea en el archivo.

Aparte de eso, y de las otras respuestas proporcionadas hasta el momento, creo que es hora de mostrar un ejemplo representativo del código del problema. Hay demasiadas posibilidades esotéricas.

EDITAR

Desde el aspecto del código de ejemplo, si usted tiene una cantidad relativamente pequeña de la impresión pasando, a continuación, que está recibiendo atrapados en el búfer de salida. Enjuague después de cada escritura para asegurarse de que se haya ido al disco. Por lo general, puede tener hasta el tamaño de una página de datos no escritos que se encuentran de otra manera.

En ausencia de una descarga, la única vez que puede estar seguro de que tiene todo en disco es cuando sale el programa . Incluso una terminación de subproceso no lo hará, ya que los búferes de salida como ese no son por subproceso, son por proceso.

+0

No pude reproducirlo en un programa pequeño y el programa original es demasiado grande para publicarlo. Trataré de mostrar algún código de todos modos. – mmutilva

6

La limpieza de los búferes normalmente se realiza mediante la función exit(), que normalmente se llama implícitamente por return desde main(). Estás finalizando tu programa al generar SIGINT, y aparentemente el controlador SIGINT predeterminado no vacía los búferes.

Echa un vistazo a este artículo: Applying Design Patterns to Simplify Signal Handling. El artículo es principalmente C++, pero hay un ejemplo C útil en la segunda sección, que muestra cómo usar SIGINT para salir de su programa con elegancia.

En cuanto a por qué el comportamiento de un terminal difiere de un archivo, eche un vistazo a la Sección 5.4 de Stevens 'Advanced Programing in the UNIX Environment sobre almacenamiento en búfer. Él dice que:

La mayoría de las implementaciones tienen por defecto los siguientes tipos de almacenamiento en búfer. El error estándar siempre está sin búfer. El resto de las transmisiones se almacenan en línea si se refieren a un dispositivo terminal; de lo contrario, están completamente amortiguados. Las cuatro plataformas analizadas en este libro siguen estas convenciones para el almacenamiento en memoria intermedia de E/S estándar: el error estándar no se almacena, las secuencias abiertas para los dispositivos terminales se almacenan en búfer de línea y todas las demás secuencias están completamente almacenadas.
0

Sugerencias:

  1. redirección stderr a un archivo así.
  2. Prueba tail -f tus archivos de salida.
  3. Abra un archivo e imprima su registro (para ayudar a descubrir qué está pasando).
  4. Busque cualquier cierre manual/duplicación/tubería de std * identificadores de ARCHIVOS o 1-3 descriptores de archivos.
  5. Reduce la complejidad; corta grandes porciones de funcionalidad hasta que printfs funcione. Luego léalos hasta que se rompa nuevamente. Continúe hasta que identifique el código culpable.
0

Sólo para que conste, en Perl se debería utilizar:

use IO::Handle; 

flush STDOUT; 
autoflush STDOUT; 
Cuestiones relacionadas