Explicação da saída do Head Script

3

Então, este script de shell:

#!/bin/bash
head >/dev/null;
head;

quase sempre dá a mesma saída quando chamado com números sequenciais (por exemplo, seq 10000 | ./sscript)

OUPUT:

     //blank line
1861
1862
1863
1864
1865
1866
1867
1868
1869

Eu usei strace seq 10000 | ./sscript , mas não consegui explicar para mim mesmo de onde exatamente esses números vêm. No final da sequência:

write(1, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14"..., 4096) = 4096
write(1, "1\n1042\n1043\n1044\n1045\n1046\n1047\n"..., 4096) = 4096
write(1, "\n1861\n1862\n1863\n1864\n1865\n1866\n1"..., 4096) = 4096
write(1, "2680\n2681\n2682\n2683\n2684\n2685\n26"..., 4096) = 4096
write(1, "499\n3500\n3501\n3502\n3503\n3504\n350"..., 4096) = 4096
write(1, "18\n4319\n4320\n4321\n4322\n4323\n4324"..., 4096) = 4096
write(1, "7\n5138\n5139\n5140\n5141\n5142\n5143\n"..., 4096) = 4096
write(1, "\n5957\n5958\n5959\n5960\n5961\n5962\n5"..., 4096) = 4096
write(1, "6776\n6777\n6778\n6779\n6780\n6781\n67"..., 4096) = 4096
write(1, "595\n7596\n7597\n7598\n7599\n7600\n760"..., 4096) = 4096
write(1, "14\n8415\n8416\n8417\n8418\n8419\n8420"..., 4096) = 4096
write(1, "3\n9234\n9235\n9236\n9237\n9238\n9239\n"..., 3838) = 3838

Por que somente o terceiro write é retornado (às vezes apenas o segundo)?

Na verdade, apenas os 10 primeiros da linha retornada (3ª ou 2ª gravação) são impressos devido ao segundo head no script, mas ainda perdidos.

    
por user4425098 25.01.2016 / 01:09

1 resposta

3

head imprime 10 linhas por padrão, mas lê o máximo de entradas possíveis - note que o GNU head possui opções que requerem que você saiba quantas linhas existem no arquivo no total, então ler o quanto puder não é errado.

head lê o máximo possível para preencher seu buffer, que parece ter 8192 bytes:

~ seq 10000 | strace -fe read ./foo.sh
read(3, "7ELF
The lseek() function shall fail if:

...

ESPIPE The fildes argument is associated with a pipe, FIFO, or socket.
~ seq 10000 | strace -fe lseek ./foo.sh
...
Process 18561 attached
[pid 18561] lseek(0, -8171, SEEK_CUR)   = -1 ESPIPE (Illegal seek)
[pid 18561] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=18561, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
Process 18562 attached
[pid 18562] lseek(0, -8146, SEEK_CUR)   = -1 ESPIPE (Illegal seek)
...
~ seq 10000 | strace -fe read ./foo.sh
read(3, "7ELF
The lseek() function shall fail if:

...

ESPIPE The fildes argument is associated with a pipe, FIFO, or socket.
~ seq 10000 | strace -fe lseek ./foo.sh
...
Process 18561 attached
[pid 18561] lseek(0, -8171, SEEK_CUR)   = -1 ESPIPE (Illegal seek)
[pid 18561] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=18561, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
Process 18562 attached
[pid 18562] lseek(0, -8146, SEEK_CUR)   = -1 ESPIPE (Illegal seek)
...
%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%>%pre%%pre%%pre%%pre%0e%pre%%pre%%pre%%pre%%pre%"..., 832) = 832 ... Process 17610 attached ... [pid 17610] read(0, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14"..., 8192) = 8192 ... [pid 17611] read(0, "\n1861\n1862\n1863\n1864\n1865\n1866\n1"..., 8192) = 8192 ...
%pre%%pre%%pre%%pre%%pre%%pre%%pre%>%pre%%pre%%pre%%pre%0e%pre%%pre%%pre%%pre%%pre%"..., 832) = 832 ... Process 17610 attached ... [pid 17610] read(0, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14"..., 8192) = 8192 ... [pid 17611] read(0, "\n1861\n1862\n1863\n1864\n1865\n1866\n1"..., 8192) = 8192 ...

Como as duas primeiras gravações têm 4096 bytes cada, elas podem ser consumidas pela primeira head .

Isso depende do tempo. Se seq só conseguiu obter um write de distância quando o primeiro head imprimiu 10 linhas e saiu, então o segundo write será obtido pelo segundo head .

O comentário do mikeserv está esclarecendo:

you should try it w/ a regular file.

seq 10000 >/tmp/nums; yourscript </tmp/nums

A razão pela qual isso se comporta como seria de esperar é que head tenta reposicionar o ponto de leitura atual para a linha após os que ele emitiu usando lseek() . Isso funciona para arquivos normais, arquivos redirecionados etc., mas não funciona para pipes:

%pre%

Como pode ser visto usando strace :

%pre%     
por 25.01.2016 / 01:30