GNU/Linux >> Tutoriales Linux >  >> Linux

redirección de salida sobre la marcha, viendo la salida de redirección de archivos mientras el programa aún se está ejecutando

Del stdout página de manual:

El flujo estándar stderr no tiene búfer. El flujo estándar stdout tiene un búfer de línea cuando apunta a una terminal .Las líneas parciales no aparecerán hasta que se llame fflush(3) o exit(3), o se imprima una nueva línea.

En pocas palabras:a menos que la salida sea una terminal, su programa tendrá su salida estándar en modo de búfer completo de forma predeterminada. Básicamente, esto significa que generará datos en bloques grandes, en lugar de línea por línea, y mucho menos carácter por carácter.

Maneras de evitar esto:

  • Arregle su programa:si necesita una salida en tiempo real, necesita arreglar su programa. En C puedes usar fflush(stdout) después de cada declaración de salida, o setvbuf() para cambiar el modo de almacenamiento en búfer de la salida estándar. Para Python hay sys.stdout.flush() de incluso algunas de las sugerencias aquí.

  • Use una utilidad que pueda grabar desde un PTY, en lugar de redirecciones directas de salida estándar. GNU Screen puede hacer esto por usted:

    screen -d -m -L python test.py
    

    sería un comienzo. Esto registrará la salida de su programa en un archivo llamado screenlog.0 (o similar) en su directorio actual con un retraso predeterminado de 10 segundos, y puede usar screen para conectarse a la sesión donde se está ejecutando su comando para proporcionar una entrada o terminarla. El retraso y el nombre del archivo de registro se pueden cambiar en un archivo de configuración o manualmente una vez que se conecte a la sesión en segundo plano.

EDITAR:

En la mayoría de los sistemas Linux, existe una tercera solución alternativa:puede usar el LD_PRELOAD variable y una biblioteca precargada para anular las funciones seleccionadas de la biblioteca C y usarlas para establecer el stdout modo de almacenamiento en búfer cuando esas funciones son llamadas por su programa. Este método puede funcionar, pero tiene una serie de desventajas:

  • No funcionará en absoluto en ejecutables estáticos

  • Es frágil y bastante feo.

  • No funcionará en absoluto con los ejecutables SUID:el cargador dinámico se negará a leer el LD_PRELOAD variable al cargar tales ejecutables por razones de seguridad.

  • Es frágil y bastante feo.

  • Requiere que encuentre y anule una función de biblioteca a la que llama su programa después inicialmente establece el stdout modo de almacenamiento en búfer y preferiblemente antes cualquier salida. getenv() es una buena opción para muchos programas, pero no para todos. Es posible que deba anular funciones de E/S comunes como printf() o fwrite() - si llega el momento, es posible que deba anular todas las funciones que controlan el modo de almacenamiento en búfer e introducir una condición especial para stdout .

  • Es frágil y bastante feo.

  • Es difícil asegurarse de que no haya efectos secundarios no deseados. Para hacer esto correctamente, debe asegurarse de que solo stdout se ve afectado y que sus anulaciones no bloquearán el resto del programa si, p. stdout está cerrado.

  • ¿Mencioné que es frágil y bastante feo?

Dicho esto, el proceso es relativamente simple. Pones un archivo C, p. linebufferedstdout.c las funciones de reemplazo:

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>


char *getenv(const char *s) {
    static char *(*getenv_real)(const char *s) = NULL;

    if (getenv_real == NULL) {
        getenv_real = dlsym(RTLD_NEXT, "getenv");

        setlinebuf(stdout);
    }

    return getenv_real(s);
}

Luego compilas ese archivo como un objeto compartido:

gcc -O2 -o linebufferedstdout.so -fpic -shared linebufferedstdout.c -ldl -lc

Luego configuras el LD_PRELOAD variable para cargarlo junto con su programa:

$ LD_PRELOAD=./linebufferedstdout.so python test.py | tee -a test.out 
0
1000
2000
3000
4000

Si tiene suerte, su problema se resolverá sin desafortunados efectos secundarios.

Puede establecer el LD_PRELOAD biblioteca en el shell, si es necesario, o incluso especificar esa biblioteca en todo el sistema (definitivamente NO recomendado) en /etc/ld.so.preload .


¿Has pensado en hacer ribetes en T?

./program | tee a.txt

Sin embargo, incluso tee no funcionará si el "programa" no escribe nada en stdout hasta que esté listo. Entonces, la efectividad depende mucho de cómo se comporte su programa.


Si está tratando de modificar el comportamiento de un programa existente, pruebe con stdbuf (aparentemente parte de coreutils que comienza con la versión 7.5).

Esto almacena la salida estándar hasta una línea:

stdbuf -oL command > output

Esto deshabilita el almacenamiento en búfer estándar por completo:

stdbuf -o0 command > output


Linux
  1. Lea y escriba datos desde cualquier lugar con redirección en la terminal de Linux

  2. Cómo redirigir la salida a un archivo y salida estándar en Linux

  3. ¿Cómo redirigir la salida de un programa a un archivo zip?

  4. Salida a Stdout y al mismo tiempo Grep en un archivo?

  5. ¿Qué forma de redirigir la salida de un programa y todavía hacer que vaya a la salida estándar?

¿Comando para enviar el contenido del archivo a la salida estándar?

¿Cerrar la salida estándar (>&-)?

¿Redireccionamiento de Io y el comando principal?

Cómo redirigir la salida a un archivo y stdout

¿Cómo agregar la salida a un archivo?

Utilizó accidentalmente la redirección de salida > en lugar de una tubería |