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)
Esse comando é gerado 1234512345
conforme o esperado. Mas isso funciona apenas na implementação coreutilshead
do utilitário. A implementação do busybox ainda consome caracteres extras, então a saída é apenas 12345
.
Acho que essa forma específica de implementação é feita para fins de otimização. Você não pode saber onde a linha termina, então não sabe quantos caracteres precisa ler. A única maneira de não consumir caracteres extras do fluxo de entrada é ler o fluxo byte por byte. Mas a leitura do fluxo um byte por vez pode ser lenta. Então, acho que head
lê o fluxo de entrada em um buffer grande o suficiente e, em seguida, conta as linhas nesse buffer.
O mesmo não pode ser dito para o caso em que a --bytes
opção é usada. Neste caso, você sabe quantos bytes precisa ler. Portanto, você pode ler exatamente esse número de bytes e não mais do que isso. A implementação corelibs usa essa oportunidade, mas a busybox não, ela ainda lê mais bytes do que o necessário em um buffer. Provavelmente é 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ê tem que pressionar Ctrl+C
para parar os comandos acima. Os utilitários Unix não falham na leitura além de 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 eu não usei para simplificar.