2009-09-15 15 views
47

que tienen un pequeño script, que se llama a diario por crontab usando el siguiente comando:Fuerza enrojecimiento de la salida a un archivo de escritura del golpe, mientras que todavía se está ejecutando

/homedir/MyScript &> some_log.log 

El problema con este método es que some_log.log solo se crea después de que MyScript finaliza. Me gustaría eliminar la salida del programa en el archivo mientras se está ejecutando por lo que podía hacer cosas como

tail -f some_log.log 

y realizar un seguimiento del progreso, etc.

+0

Tendremos que tener una descripción, o si es posible un código, de lo que hace exactamente tu pequeña secuencia de comandos ... – ChristopheD

+4

Para desvincular las secuencias de comandos de python puedes usar "python -u". Para desvincular las secuencias de comandos de perl, consulte la respuesta de Greg Hewgill a continuación. Y así sucesivamente ... – Eloici

+0

Si puede editar la secuencia de comandos, generalmente puede vaciar el búfer de salida de forma explícita dentro de una secuencia de comandos, por ejemplo, en python con 'sys.stdout.flush()'. – drevicko

Respuesta

21

bash nunca escribirá ninguna salida en su archivo de registro. En cambio, los comandos que invoca como parte de la secuencia de comandos escribirán cada salida individualmente y ruborizar cada vez que lo deseen. Entonces su pregunta es realmente cómo forzar los comandos dentro del script bash para que se vayan, y eso depende de lo que sean.

+1

Gracias, eso aclaro el problema un poco. – olamundo

+2

Realmente no entiendo esta respuesta. –

+2

Para obtener una mejor idea de por qué la salida estándar se comporta de esta manera, consulte http://stackoverflow.com/a/13933741/282728. Una versión corta: de forma predeterminada, si se redirige a un archivo, stdout está completamente almacenado en el búfer; está escrito en un archivo solo después de un color. Stderr no está escrito después de cada '\ n'. Una solución es usar el comando 'script' recomendado por user3258569 a continuación, para que se elimine el stdout después de cada final de línea. – Alex

2

Esto no es una función de bash , como todo lo que hace Shell es abrir el archivo en cuestión y luego pasar el descriptor de archivo como salida estándar del script. Lo que debe hacer es asegurarse de que la salida se vacíe de su secuencia de comandos con más frecuencia que la que tiene actualmente.

En Perl, por ejemplo, esto podría lograrse mediante el establecimiento de:

$| = 1; 

Ver perlvar para más información sobre esto.

-1

No sé si funcionaría, pero ¿qué hay de llamar al sync?

+0

'sync' es una operación de bajo nivel del sistema de archivos y no está relacionada con la salida almacenada en el nivel de aplicación. –

+1

Dado que puede llamar a la sincronización como un comando, ¿qué hace, entonces? – forkandwait

+2

'sync' escribe cualquier búfer sucio del sistema de archivos en el almacenamiento físico, si es necesario. Esto es interno al sistema operativo; las aplicaciones que se ejecutan en la parte superior del sistema operativo siempre ven una vista coherente del sistema de archivos, ya sea que los bloques de disco se hayan escrito o no en el almacenamiento físico. Para la pregunta original, la aplicación (script) probablemente está almacenando en búfer el resultado en un búfer interno de la aplicación, y el sistema operativo ni siquiera sabrá (todavía) que la salida está realmente destinada a escribirse en stdout. Por lo tanto, una operación hipotética de tipo "sincronización" no sería capaz de "alcanzar" el script y extraer los datos. –

-2

les gusta o no así es como funciona la redirección.

En su caso, el resultado (es decir, el guión finalizado) de su secuencia de comandos redirigido a ese archivo.

Lo que quiere hacer es agregar esas redirecciones en su secuencia de comandos.

-1

Tuve este problema con un proceso en segundo plano en Mac OS X usando el StartupItems. Así es como lo resuelvo:

Si hago sudo ps aux puedo ver que se inicia mytool.

Encontré que (debido al almacenamiento en búfer) cuando Mac OS X se apaga mytool nunca transfiere la salida al comando sed. Sin embargo, si ejecuto sudo killall mytool, entonces mytool transfiere la salida al comando sed. Por lo tanto, he añadido un caso stop a la StartupItems que se ejecuta cuando Mac OS X se apaga:

start) 
    if [ -x /sw/sbin/mytool ]; then 
     # run the daemon 
     ConsoleMessage "Starting mytool" 
     (mytool | sed .... >> myfile.txt) & 
    fi 
    ;; 
stop) 
    ConsoleMessage "Killing mytool" 
    killall mytool 
    ;; 
8

Puede utilizar tee escribir en el archivo sin la necesidad de enjuagar.

/homedir/MyScript 2>&1 | tee some_log.log > /dev/null 
8

script -c <PROGRAM> -f OUTPUT.txt

clave es -F. Presupuesto de la escritura del hombre:

-f, --flush 
     Flush output after each write. This is nice for telecooperation: one person does `mkfifo foo; script -f foo', and another can supervise real-time what is being done 
     using `cat foo'. 

Ejecutar en segundo plano:

nohup script -c <PROGRAM> -f OUTPUT.txt 
1

Como acaba de manchar here el problema es que usted tiene que esperar que los programas que se ejecutan desde el script terminan su trabajos.
Si en su secuencia de comandos ejecuta el programa en fondo puede intentar algo más.

En general, una llamada al sync antes de salir permite vaciar los búferes del sistema de archivos y puede ayudar un poco.

Si en la secuencia de comandos se inician algunos programas en fondo (&), puede wait que terminar antes de que salga de la secuencia de comandos. Para tener una idea acerca de cómo puede funcionar se puede ver a continuación

#!/bin/bash 
#... some stuffs ... 
program_1 &   # here you start a program 1 in background 
PID_PROGRAM_1=${!} # here you remember its PID 
#... some other stuffs ... 
program_2 &   # here you start a program 2 in background 
wait ${!}   # You wait it finish not really useful here 
#... some other stuffs ... 
daemon_1 &   # We will not wait it will finish 
program_3 &   # here you start a program 1 in background 
PID_PROGRAM_3=${!} # here you remember its PID 
#... last other stuffs ... 
sync 
wait $PID_PROGRAM_1 
wait $PID_PROGRAM_3 # program 2 is just ended 
# ... 

Desde wait trabajos con puestos de trabajo, así como con PID números de una solución perezosa debe ser poner al final de la secuencia de comandos

for job in `jobs -p` 
do 
    wait $job 
done 

Más difícil es la situación si ejecuta algo que ejecuta otra cosa en segundo plano porque tiene que buscar y esperar (si es el caso) el final de todo el proceso hijo: por ejemplo, si ejecuta daemon probablemente no lo es el caso de esperar termina :-).

Nota:

  • espera $ significa "esperar hasta el último proceso en segundo plano se ha completado", donde $! es el PID del último proceso de fondo {!}. Así que para poner wait ${!} justo después program_2 & es equivalente a ejecutar directamente program_2 sin enviarlo en el fondo con &

  • De la ayuda de wait:

    Syntax  
        wait [n ...] 
    Key 
        n A process ID or a job specification 
    
43

he encontrado una solución a este here. Usando el ejemplo de la OP básicamente ejecuta

stdbuf -oL /homedir/MyScript &> some_log.log

y luego el buffer se vacía después de cada línea de salida. A menudo combino esto con nohup para ejecutar trabajos largos en una máquina remota.

stdbuf -oL nohup /homedir/MyScript &> some_log.log

De esta manera el proceso no se cancelan al cerrar la sesión.

+1

¿Podría agregar un enlace a alguna documentación para 'stdbuf'? Basado en [este comentario] (http://stackoverflow.com/questions/1429951/bash-how-to-flush-output-to-a-file-while-running?answertab=votes#comment4951700_4520994) parece que no es disponible en algunas distros. ¿Podrías aclarar? –

+0

stdbuf -o ajusta el almacenamiento en búfer de stdout. Las otras opciones son -i y -e para stdin y stderr. L establece el almacenamiento en línea de la línea. También se podría especificar el tamaño del buffer, o 0 para no buffering. –

+2

ese enlace ya no está disponible. –

1

El almacenamiento en búfer de la salida depende de cómo se implemente su programa /homedir/MyScript. Si encuentra que la salida está siendo amortiguada, debe forzarla en su implementación. Por ejemplo, use sys.stdout.flush() si es un programa python o use fflush (stdout) si se trata de un programa C.

Cuestiones relacionadas