Aparentemente, head
de fato distorce sua entrada quando não é um arquivo de texto:
$ wc /bin/ls
431 3454 126496 /bin/ls
$ head -n 431 /bin/ls > a
wc a
431 3447 125378 a
$ diff a /bin/ls
Binary files a and /bin/ls differ
$ md5sum /bin/ls a
42846aa64774a99f0f1feba36ec2e099 /bin/ls
de032f5aa5ef356fb7d5ab4dc622df2e a
$ wc -c /bin/ls a
126496 /bin/ls
125378 a
Stéphane Chazelas faz um bom ponto nos comentários:
wc -l
reports the number of newlines. /bin/ls
likely has more bytes after the last occurrence of 0xa
, which head -n 431
won't output. GNU tools (which you seem to be using) generally can deal with binary data (NUL bytes and arbitrarily long lines).
Portanto, o motivo pelo qual a saída está errada ao usar head -n
é que há dados extras após o último caractere \n
. Olhando para o código-fonte para o GNU head
, posso confirmar que tanto a função que lê por linhas quanto a que lê por bytes, usa a mesma chamada safe_open()
, então não deveria haver nenhuma diferença entre o que eles são capazes de retornar. Isso sugeriria que usar a implementação GNU de head
(como normalmente é encontrado na maioria dos sistemas operacionais não-embarcados usando Linux) é bastante seguro.
No entanto, parece que funciona corretamente se você disser para trabalhar em bytes em vez de linhas (de man head
):
-c, --bytes=[-]NUM
print the first NUM bytes of each file; with the leading '-',
print all but the last NUM bytes of each file
Com a opção -c
, parece criar arquivos idênticos:
$ wc -c /bin/ls
126496 /bin/ls
$ head -c 126496 /bin/ls > a
$
$ md5sum /bin/ls a
42846aa64774a99f0f1feba36ec2e099 /bin/ls
42846aa64774a99f0f1feba36ec2e099 a
Este também é o mesmo resultado obtido por dd
:
$ dd if=/bin/ls of=a bs=126496 count=1
1+0 records in
1+0 records out
126496 bytes (126 kB, 124 KiB) copied, 0.000469919 s, 269 MB/s
$ diff a /bin/ls
$
Não consigo apontar para nenhuma documentação oficial que especifique que, ao usar o sinal -c
, ele sempre produzirá a saída binária correta, mas parece uma suposição razoável a ser feita.