GNU/Linux >> Linux Esercitazione >  >> Linux

reindirizzamento dell'output al volo, visualizzando l'output del reindirizzamento del file mentre il programma è ancora in esecuzione

Dal stdout pagina di manuale:

Lo stream stderr non è bufferizzato. Lo stream stdout è bufferizzato di rigaquando punta a un terminale .Le righe parziali non appariranno fino a quando non viene chiamato fflush(3) o exit(3), o viene stampata una nuova riga.

In conclusione:a meno che l'output non sia un terminale, il tuo programma avrà il suo output standard in modalità completamente bufferizzata per impostazione predefinita. Ciò significa essenzialmente che produrrà i dati in blocchi di grandi dimensioni, piuttosto che riga per riga, figuriamoci carattere per carattere.

Modi per aggirare questo problema:

  • Correggi il tuo programma:se hai bisogno di output in tempo reale, devi correggere il tuo programma. In C puoi usare fflush(stdout) dopo ogni istruzione di output, o setvbuf() per modificare la modalità di buffering dell'output standard. Per Python c'è sys.stdout.flush() anche di alcuni dei suggerimenti qui.

  • Utilizzare un'utilità in grado di registrare da un PTY, piuttosto che reindirizzamenti stdout diretti. GNU Screen può fare questo per te:

    screen -d -m -L python test.py
    

    sarebbe un inizio. Questo registrerà l'output del tuo programma in un file chiamato screenlog.0 (o simile) nella directory corrente con un ritardo predefinito di 10 secondi e puoi utilizzare screen per connettersi alla sessione in cui è in esecuzione il comando per fornire input o terminarlo. Il ritardo e il nome del file di registro possono essere modificati in un file di configurazione o manualmente dopo esserti connesso alla sessione in background.

MODIFICA:

Sulla maggior parte dei sistemi Linux c'è una terza soluzione alternativa:puoi usare il LD_PRELOAD variabile e una libreria precaricata per sovrascrivere funzioni selezionate della libreria C e utilizzarle per impostare il stdout modalità di buffering quando tali funzioni vengono chiamate dal programma. Questo metodo può funzionare, ma presenta una serie di svantaggi:

  • Non funzionerà affatto su eseguibili statici

  • È fragile e piuttosto brutto.

  • Non funzionerà affatto con gli eseguibili SUID:il caricatore dinamico si rifiuterà di leggere LD_PRELOAD variabile durante il caricamento di tali eseguibili per motivi di sicurezza.

  • È fragile e piuttosto brutto.

  • Richiede che tu trovi e sovrascriva una funzione di libreria che viene chiamata dal tuo programma dopo inizialmente imposta il stdout modalità buffering e preferibilmente prima qualsiasi uscita. getenv() è una buona scelta per molti programmi, ma non per tutti. Potrebbe essere necessario eseguire l'override delle comuni funzioni di I/O come printf() o fwrite() - se arriva il momento critico potresti semplicemente dover sovrascrivere tutte le funzioni che controllano la modalità di buffering e introdurre una condizione speciale per stdout .

  • È fragile e piuttosto brutto.

  • È difficile garantire che non ci siano effetti collaterali indesiderati. Per farlo correttamente dovresti assicurarti che solo stdout è interessato e che le tue sostituzioni non bloccheranno il resto del programma se ad es. stdout è chiuso.

  • Ho già detto che è fragile e piuttosto brutto?

Detto questo, il processo è relativamente semplice. Hai inserito un file C, ad es. linebufferedstdout.c le funzioni di sostituzione:

#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);
}

Quindi compili quel file come oggetto condiviso:

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

Quindi imposti il ​​LD_PRELOAD variabile per caricarla insieme al tuo programma:

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

Se sei fortunato, il tuo problema sarà risolto senza sfortunati effetti collaterali.

Puoi impostare il LD_PRELOAD libreria nella shell, se necessario, o anche specificare quella libreria a livello di sistema (sicuramente NON consigliato) in /etc/ld.so.preload .


Hai preso in considerazione il piping to tee?

./program | tee a.txt

Tuttavia, anche tee non funzionerà se "program" non scrive nulla su stdout finché non è terminato. Quindi, l'efficacia dipende molto da come si comporta il tuo programma.


Se stai cercando di modificare il comportamento di un programma esistente, prova stdbuf (apparentemente parte di coreutils a partire dalla versione 7.5).

Questo bufferizza lo stdout fino a una riga:

stdbuf -oL command > output

Questo disabilita del tutto il buffering stdout:

stdbuf -o0 command > output


Linux
  1. Come reindirizzare l'output su un file e Stdout in Linux

  2. Come modificare il reindirizzamento dell'output di un processo in esecuzione?

  3. Output del contenuto del file mentre cambiano?

  4. Come reindirizzare l'output su un file e stdout

  5. emette la seconda colonna di un file

Comando per inviare il contenuto del file a Stdout?

Chiusura dell'output standard (>&-)?

Io reindirizzamento e il comando principale?

Come aggiungere l'output a un file?

Come reindirizzare l'output di system() su un file?

Determina se l'output è stdout o stderr