Esiste una regola di buffering generale seguita dalla libreria I / O standard C ( stdio
) utilizzata dalla maggior parte dei programmi unix. Se l'uscita sta per un terminale, viene scaricata alla fine di ogni riga; altrimenti viene scaricato solo quando il buffer (8K sul mio sistema Linux / amd64; potrebbe essere diverso sul tuo) è pieno.
Se tutte le utilità seguivano la regola generale, si dovrebbe vedere l'uscita in ritardo in tutti i tuoi esempi ( cat|sed
, cat|tr
, e cat|tr|sed
). Ma c'è un'eccezione: GNU cat
non bufferizza mai il suo output. Non utilizza stdio
o modifica la stdio
politica di buffering predefinita .
Posso essere abbastanza sicuro che stai usando GNU cat
e non qualche altro unix cat
perché gli altri non si comporteranno in questo modo. Unix tradizionale cat
ha -u
un'opzione per richiedere output senza buffer. GNU cat
ignora l' -u
opzione perché il suo output è sempre senza buffer.
Quindi ogni volta che si ha una pipe con a cat
sulla sinistra, nel sistema GNU, il passaggio dei dati attraverso la pipe non sarà ritardato. Non cat
sta nemmeno andando riga per riga: il tuo terminale lo sta facendo. Mentre digiti input per cat, il tuo terminale è in modalità "canonica" - basata su linea, con tasti di modifica come backspace e ctrl-U che ti offrono la possibilità di modificare la linea che hai digitato prima di inviarlo con Enter.
Nel cat|tr|sed
esempio, tr
è ancora ricevere dati da cat
appena si preme Enter, ma tr
sta seguendo il stdio
criterio predefinito: la sua uscita sta per un tubo, in modo che non filo dopo ogni riga. Scrive sulla seconda pipe quando il buffer è pieno o quando viene ricevuto un EOF, a seconda di quale evento si verifica per primo.
sed
sta anche seguendo la stdio
politica di default, ma il suo output sta andando su un terminale, quindi scriverà ogni riga non appena avrà finito con esso. Questo ha un effetto su quanto devi digitare prima che qualcosa appaia sull'altra estremità della pipeline - se il sed
buffering del blocco fosse il suo output, dovresti digitare il doppio (per riempire tr
il buffer di output e sed
l'output buffer).
GNU sed
ha -u
un'opzione, quindi se si inverte l'ordine e si utilizza cat|sed -u|tr
, l'output verrà visualizzato di nuovo immediatamente. (L' sed -u
opzione potrebbe essere disponibile altrove ma non credo che sia un'antica tradizione unix come cat -u
) Per quanto posso dire non esiste un'opzione equivalente per tr
.
Esiste un'utilità chiamata stdbuf
che consente di modificare la modalità di buffering di qualsiasi comando che utilizza le stdio
impostazioni predefinite. È un po 'fragile poiché utilizza LD_PRELOAD
per realizzare qualcosa che la libreria C non è stata progettata per supportare, ma in questo caso sembra funzionare:
cat | stdbuf -o 0 tr '[:lower:]' '[:upper:]' | sed 'p'
cat
buffering fino alla chiusura di stdin.