Existe uma regra de buffer geral seguida pela biblioteca de I / O padrão C ( stdio ) que a maioria dos programas unix usa. Se a saída estiver indo para um terminal, ela será liberada no final de cada linha; caso contrário, ele será liberado apenas quando o buffer (8K no meu sistema Linux / amd64; puder ser diferente no seu) estiver cheio.
Se todos os seus utilitários estivessem seguindo a regra geral, você veria a saída atrasada em todos os seus exemplos ( cat|sed , cat|tr e cat|tr|sed ). Mas há uma exceção: GNU cat nunca armazena sua saída. Ele não usa stdio ou altera a política de buffer stdio padrão.
Posso ter certeza de que você está usando o GNU cat e não algum outro unix cat porque os outros não se comportariam dessa maneira. O unix tradicional cat tem uma opção -u para solicitar saída sem buffer. O GNU cat ignora a opção -u porque sua saída está sempre sem buffer.
Portanto, sempre que você tiver um canal com cat à esquerda, no sistema GNU, a passagem de dados pelo canal não será atrasada. O cat não está nem seguindo linha por linha - seu terminal está fazendo isso. Enquanto você digita entrada para cat, seu terminal está no modo "canônico" - baseado em linha, com teclas de edição como backspace e ctrl-U oferecendo a chance de editar a linha que você digitou antes de enviá-la com Enter .
No cat|tr|sed example, tr ainda está recebendo dados de cat assim que você pressionar Enter , mas tr está seguindo a política padrão stdio : sua saída está indo para um pipe, então ele não flush após cada linha. Ele grava no segundo pipe quando o buffer está cheio ou quando um EOF é recebido, o que ocorrer primeiro.
sed também está seguindo a política padrão stdio , mas sua saída está indo para um terminal, portanto, ele gravará cada linha assim que tiver terminado. Isso tem um efeito sobre o quanto você deve digitar antes que algo apareça na outra extremidade do pipeline - se sed estivesse armazenando em buffer o seu resultado, você teria que digitar duas vezes mais (para preencher tr 's buffer de saída e sed do buffer de saída).
GNU sed tem -u , por isso, se você inverteu a ordem e usou cat|sed -u|tr , verá a saída aparecer instantaneamente novamente. (A opção sed -u pode estar disponível em outro lugar, mas eu não acho que seja uma tradição antiga do unix como cat -u ). Até onde eu sei, não existe uma opção equivalente para tr .
Existe um utilitário chamado stdbuf que permite alterar o modo de armazenamento em buffer de qualquer comando que use os stdio defaults. É um pouco frágil, pois usa LD_PRELOAD para realizar algo que a biblioteca C não foi projetada para suportar, mas, neste caso, parece funcionar:
cat | stdbuf -o 0 tr '[:lower:]' '[:upper:]' | sed 'p'