Esperava-se que o seguinte comando shell imprimisse apenas linhas ímpares do fluxo de entrada:
echo -e "aaa\nbbb\nccc\nddd\n" | (while true; do head -n 1; head -n 1 >/dev/null; done)
Mas em vez disso, apenas imprime a primeira linha: aaa
.
O mesmo não acontece quando usado com a opção -c
( --bytes
):
echo 12345678901234567890 | (while true; do head -c 5; head -c 5 >/dev/null; done)
Este comando é exibido 1234512345
conforme o esperado. Mas isso funciona apenas na implementação de coreutils do head
utilitário. A implementação do busybox ainda consome caracteres extras, portanto a saída é justa 12345
.
Eu acho que essa maneira específica de implementação é feita para fins de otimização. Você não pode saber onde a linha termina, portanto, não sabe quantos caracteres precisa ler. A única maneira de não consumir caracteres extras do fluxo de entrada é ler o fluxo byte a byte. Mas a leitura do fluxo, um byte de cada vez, pode ser lenta. Então, eu acho que head
lê o fluxo de entrada em um buffer grande o suficiente e depois conta as linhas nesse buffer.
O mesmo não pode ser dito para o caso em que a --bytes
opção é usada. Nesse caso, você sabe quantos bytes precisa ler. Então você pode ler exatamente esse número de bytes e não mais do que isso. A implementação do corelibs usa essa oportunidade, mas a do busybox não, ela ainda lê mais bytes do que o necessário em um buffer. Provavelmente isso é feito para simplificar a implementação.
Então a pergunta. É correto que o head
utilitário consuma mais caracteres do fluxo de entrada do que o solicitado? Existe algum tipo de padrão para utilitários Unix? E se houver, ele especifica esse comportamento?
PS
Você precisa pressionar Ctrl+C
para interromper os comandos acima. Os utilitários Unix não falham na leitura além EOF
. Se você não quiser pressionar, pode usar um comando mais complexo:
echo 12345678901234567890 | (while true; do head -c 5; head -c 5 | [ `wc -c` -eq 0 ] && break >/dev/null; done)
que não usei por simplicidade.