2010-07-26 18 views
20

Tengo un guión como:bash: proceso exec'd fuerza para tener la salida estándar sin búfer

#!/bin/bash 
exec /usr/bin/some_binary > /tmp/my.log 2>&1 

problema es que some_binary envía toda su registro a la salida estándar, y buffering hace de manera que sólo veo salida en trozos de algunas líneas. Esto es molesto cuando algo se atasca y necesito ver lo que dice la última línea.

¿Hay alguna manera de hacer stdout sin búfer antes de hacer el ejecutivo que afectará a some_binary por lo que tiene un registro más útil?

(El guión envoltorio sólo se está estableciendo un par de variables de entorno antes de que el ejecutivo, por lo que una solución en Perl o Python también sería factible.)

+5

La respuesta de Dennis es * exactamente * correcta. Este es el por qué. Los programas en Unix que usan C stdio para salida almacenan en búfer cuando la salida no va a un terminal (aumenta mucho el rendimiento) a menos que se indique que no con 'setvbuf'; casi nadie se molesta con eso. El sistema 'expect' (del cual' unbuffer' es una aplicación trivial) usa magia negra con dispositivos pseudo-terminales de Unix (ptys) para ejecutar programas con un terminal que no es un terminal real para que el programa envuelto no almacene su salida. Es inteligente, pero tenga cuidado: la mayoría de los sistemas solo tienen un número limitado de ptys; un programa naturalmente sin buffer es mejor. –

+0

Por cierto, esto no funciona tan bien en Windows. Esto se debe a que en esa plataforma se espera que use magia de depuración en lugar de magia terminal (porque esta es un área donde Windows es * muy * diferente). –

+0

Gracias. Decidí optar por modificar 'some_binary' para hacer lo correcto en lugar de confiar en la magia negra. 'expect' es genial, pero no lo quiero aquí ... – bstpierre

Respuesta

13

Usted puede encontrar que el guión unbuffer que viene con expect puede ayudar.

+0

No funciona con el' echo -n .' o 'prinff". "' que necesito en mi caso mostrar una barra de progreso en bash – Davide

+0

See también: http://stackoverflow.com/questions/1401002/trick-an-application-into-thinking-its-stdin-is-interactive-not-a-pipe –

11

Algunos programas de línea de comandos tienen una opción para modificar su comportamiento de almacenamiento en búfer de corriente stdout. Así que ese es el camino a seguir si la fuente de C está disponible ...

# two command options ... 
man file | less -p '--no-buffer' 
man grep | less -p '--line-buffered' 

# ... and their respective source code 

# from: http://www.opensource.apple.com/source/file/file-6.2.1/file/src/file.c 
if(nobuffer) 
    (void) fflush(stdout); 

# from: http://www.opensource.apple.com/source/grep/grep-28/grep/src/grep.c 
if (line_buffered) 
    fflush (stdout); 

Como una alternativa al uso de esperar guión unbuffer o modificar el código fuente del programa, también puede tratar de usar la escritura (1) para evitar la salida estándar hipo causadas por un tubo:

Ver: Trick an application into thinking its stdin is interactive, not a pipe

# Linux 
script -c "[executable string]" /dev/null 

# FreeBSD, Mac OS X 
script -q /dev/null "[executable string]" 
+1

En Mac OS X, porque "script" puede cambiar return código de "\ n" a "\ r \ n", necesitaba ejecutar así: 'script -q/dev/null comandos ... | perl -pe 's/\ n/\ r \ n/g'' –

26

GNU coreutils-8.5 también tiene el comando stdbuf modificar E/S corriente de amortiguación.

http://www.pixelbeat.org/programming/stdio_buffering/

Así, en su caso de ejemplo, basta con invocar:

exec stdbuf -oL /usr/bin/some_binary > /tmp/my.log 2>&1 

Esto permitirá que aparezca inmediatamente, línea por línea (una vez a la línea se completa con el fin-de-texto línea "\n" personaje en C). Si realmente desea salida inmediata, use -o0 en su lugar.

De esta manera podría ser más conveniente si no desea introducir la dependencia a expect a través del comando unbuffer. La forma unbuffer, por otro lado, es necesaria si tiene que engañar al some_binary para que piense que se enfrenta a una salida estándar real.

2

GNU Coreutils-8 incluye un programa llamado stdbuf que esencialmente hace el truco LD_PRELOAD. Funciona en Linux y, según los informes, funciona en sistemas BSD.

2

que me recorrió la internets una respuesta, y nada de esto funcionó para uniq que es demasiado terco para amortiguar todo a excepción de stdbuf:

{piped_command_here} | stdbuf -oL uniq | {more_piped_command_here}

1

Una variable de entorno puede establecer el modo IO terminal sin búfer .

exportación NSUnbufferedIO = SÍ

Esto establecerá el no tamponada terminal para ambos comandos de salida de terminal C y Ojective-C.

Cuestiones relacionadas