Quando o arquivo de entrada é buscável (como leitura de um arquivo normal) ou inutilizável (como leitura de um pipe), sed
(e outros utilitários padrão) se comportará de maneira diferente (leia a seção INPUT FILES
em este link ).
Citação do documento:
When a standard utility reads a seekable input file and terminates without an error before it reaches end-of-file, the utility shall ensure that the file offset in the open file description is properly positioned just past the last byte processed by the utility.
Então, em:
(sed '/y/ q'; echo aaa; cat) < test
sed
executou o comando q
uit antes de atingir o EOF, então deixou o deslocamento do arquivo no início de zzz
line, então cat
pode continuar imprimindo as linhas restantes (o GNU sed não é compatível com POSIX em alguma condição, veja abaixo).
E continuando a partir do documento:
For files that are not seekable, the state of the file offset in the open file description for that file is unspecified
Nesse caso, o comportamento não é especificado. A maioria das ferramentas padrão, incluindo sed
, consumirá a entrada o máximo possível. Ele leu passar a linha yyy
e q
sem restaurar o deslocamento do arquivo, portanto, nada é deixado para cat
.
O GNU sed
não é compatível com o padrão, depende da implementação do stdio do sistema e da versão glibc:
$ (gsed '/y/ q'; echo aaa; cat) < test
xxx
yyy
aaa
Aqui, o resultado foi obtido a partir do Mac OSX 10.11.6, máquinas virtuais Centos 7.2 - glibc 2.17, Ubuntu 14.04 - glibc 2.19, que são executados em Openstack com backend CEPH.
Nesses sistemas, você pode usar a opção -u
para alcançar o comportamento padrão:
(gsed -u '/y/ q'; echo aaa; cat) </tmp/test
e para pipe:
$ cat test | (gsed -u '/y/ q'; echo aaa; cat)
xxx
yyy
aaa
zzz
que leva a um desempenho terrivelmente ineficiente, porque sed
precisa ler um byte de cada vez. Uma saída parcial de strace
:
$ strace -fe read sh -c '{ sed -u "/y/q"; echo aaa; cat; } <test'
...
[pid 5248] read(3, "", 4096) = 0
[pid 5248] read(0, "x", 1) = 1
[pid 5248] read(0, "x", 1) = 1
[pid 5248] read(0, "x", 1) = 1
[pid 5248] read(0, "\n", 1) = 1
xxx
[pid 5248] read(0, "y", 1) = 1
[pid 5248] read(0, "y", 1) = 1
[pid 5248] read(0, "y", 1) = 1
[pid 5248] read(0, "\n", 1) = 1
yyy
...