Posso disabilitare il buffering per tr


10

trsembra bufferizzare il suo input in modo che questo comando LongRunningCommand|tr \\n ,inizi a produrre output solo dopo che si sono accumulati pochi kilobyte di input da LongRunningCommand.

Esiste un modo per forzare trl'arresto di questo buffering o qualsiasi altro comando che può sostituire le nuove righe con un altro carattere senza buffering?


PS Ho già provato i primi due suggerimenti da Disattiva buffering in pipe senza successo.


1
ti sei applicato stdbufa LongRunningCommand o a tr, o ad entrambi, in modo diverso?
Meuh

Ad entrambi piace:stdbuf -o0 fping -aAq -r2 -g 10.30.0.1 10.30.0.255 2>/dev/null | stdbuf -i0 tr \\n ,
ndemou,

fping -qdice "Non mostrare i risultati per sonda, ma solo il riepilogo finale", quindi forse alla fine scrive solo una lunga?
Meuh

No, il comando fping funziona bene da solo. Molte grazie per i suggerimenti
ndemou,

2
Penso che il problema del buffering sia effettivamente nell'output di tr. Prova|stdbuf -i0 -o0 tr ...
meuh

Risposte:


12

I comandi generalmente non bufferizzano il loro input. Farebbero un read()per un grosso pezzo, ma quando leggono da una pipe, se non ci sono tanti byte nella pipe, la read()chiamata di sistema restituirà con quanti più caratteri ci sono e l'applicazione generalmente funzionerà con quella se può .

Un'eccezione notevole a ciò è mawkche rimarrà attiva read()fino a quando il buffer di input non sarà pieno.

Le applicazioni bufferizzano il loro output (stdout) però. Il comportamento normale è che se l'output sta per raggiungere un valore tty, il buffering sarà a livello di linea (ovvero, non inizierà a scrivere su stdout fino a quando non avrà una riga intera da emettere, o un blocco pieno per molto linea lunga), mentre per ogni altro tipo di file, il buffering è per blocchi (cioè, non inizierà a scrivere finché non ha un blocco pieno da scrivere (qualcosa come 4KiB / 8KiB ... dipende dal software e dal sistema )).

Quindi nel tuo caso LongRunningCommandprobabilmente buffer il suo output per blocchi (dal momento che il suo output è una pipe e non una tty), e trprobabilmente buffer il suo output per linea poiché il suo output è probabilmente il terminale.

Ma, poiché rimuovi ogni carattere di nuova riga dal suo output, non genererà mai una riga, quindi il buffering sarà a blocchi.

Quindi qui vuoi disabilitare il buffering per entrambi LongRunningCommande tr. Sui sistemi GNU o FreeBSD:

stdbuf -o0 LongRunningCommand | stdbuf -o0 tr '\n' ,

Si noti che se si desidera unire le linee con una virgola, è necessario utilizzare un approccio migliore paste -sd , -. In questo modo l'output verrà terminato da un carattere di nuova riga (probabilmente dovrai comunque disabilitare il buffering).


@mikeserv. Sì, e uno che usa il buffering stdio e non chiama setvbuf / setbuffer ... da solo e non è un built-in di shell. Ma generalmente sui sistemi GNU e FreeBSD, tutte queste condizioni sono soddisfatte.
Stéphane Chazelas,

Oh. l'ho imparato solo pochi giorni fa, quando sono rimasto deluso dal fatto di non poter influenzare i flussi di I / O per il mio compilato staticamente sed. scusate se è stato fastidioso - ma non mi rendevo conto che era conoscenza generale. immagino che usi LD_PRELOAD.
Mikeserv,

Grazie per la spiegazione approfondita di ciò che accade Stéphane. Molto apprezzato
ndemou,

5

Per sostituire le nuove righe con ",", è possibile eseguire

awk '{ printf "%s,", $0 }'

GNU awk ( gawk) e Solaris nawkfunzioneranno con buffering di linea su stdin e nessun buffering stdout quando l'output è su un terminale. Se il tuo awk è mawk, cosa che succede su Ubuntu, puoi dargli la -W interactivepossibilità di ottenere lo stesso comportamento di buffering.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.