Forza il buffering di riga dello stdout quando si esegue il piping sul tee

Di solito, lo stdout è bufferato dalla linea. In altre parole, finché il tuo argomento printf termina con una nuova riga, puoi aspettarti che la riga venga stampata immediatamente. Questo non sembra trattenere quando si usa una pipe per redirect a tee .

Ho un programma C ++, a , che emette stringhe, sempre \n -terminate, a stdout .

Quando viene eseguito da solo ( ./a ), tutto viene stampato correttamente e al momento giusto, come previsto. Tuttavia, se lo ./a | tee output.txt a tee ( ./a | tee output.txt ), non stampa nulla finché non si chiude, il che vanifica lo scopo dell’uso del tee .

So che potrei aggiustarlo aggiungendo un fflush(stdout) dopo ogni operazione di stampa nel programma C ++. Ma c’è un modo più semplice e pulito? Esiste un comando che posso eseguire, ad esempio, che costringerebbe lo stdout al buffer di riga, anche quando si usa una pipe?

Prova unbuffer che fa parte del pacchetto expect . Potresti già averlo sul tuo sistema.

puoi provare stdbuf

 $ stdbuf -o 0 ./a | tee output.txt 

(grande) parte della pagina man:

  -i, --input=MODE adjust standard input stream buffering -o, --output=MODE adjust standard output stream buffering -e, --error=MODE adjust standard error stream buffering If MODE is 'L' the corresponding stream will be line buffered. This option is invalid with standard input. If MODE is '0' the corresponding stream will be unbuffered. Otherwise MODE is a number which may be followed by one of the following: KB 1000, K 1024, MB 1000*1000, M 1024*1024, and so on for G, T, P, E, Z, Y. In this case the corresponding stream will be fully buffered with the buffer size set to MODE bytes. 

tieni questo a mente, però:

 NOTE: If COMMAND adjusts the buffering of its standard streams ('tee' does for eg) then that will override corresponding settings changed by 'stdbuf'. Also some filters (like 'dd' and 'cat' etc.) dont use streams for I/O, and are thus unaffected by 'stdbuf' settings. 

non stai stdbuf on tee , lo stai eseguendo su a , quindi questo non dovrebbe influire su di te, a meno che non imposti il ​​buffering dei flussi di a in a fonte.

Inoltre, stdbuf non è POSIX, ma parte di GNU-coreutils.

Si può anche provare ad eseguire il comando in uno pseudo-terminale usando il comando script (che dovrebbe applicare l’output bufferizzato alla linea alla pipe)!

 script -q /dev/null ./a | tee output.txt # Mac OS X, FreeBSD script -c "./a" /dev/null | tee output.txt # Linux 

Si tenga presente che il comando di script non si propaga di nuovo lo stato di uscita del comando spostato.

È ansible utilizzare setlinebuf da stdio.h.

 setlinebuf(stdout); 

Questo dovrebbe cambiare il buffering in “linea bufferizzata”.

Se hai bisogno di più flessibilità puoi usare setvbuf.

Se invece si usano le classi di stream C ++, ogni std::endl è uno svuotamento implicito. Usando la stampa in stile C, penso che il metodo che hai suggerito ( fflush() ) sia l’unico modo.