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'