Quando o arquivo de entrada é procurável (como a leitura de um arquivo normal) ou não pesquisável (como a leitura de um canal ), sed
(e outros utilitários padrão) se comportam de maneira diferente ( INPUT FILES
seção Leia neste link ).
Citação do documento:
Quando um utilitário padrão lê um arquivo de entrada procurável e termina sem erro antes de chegar ao final do arquivo, o utilitário deve garantir que o deslocamento do arquivo na descrição do arquivo aberto seja posicionado corretamente logo após o último byte processado pelo utilitário.
Então em:
(sed '/y/ q'; echo aaa; cat) < test
sed
executou o q
comando uit antes de atingir o EOF, deixando o deslocamento do arquivo no início da zzz
linha, para cat
continuar imprimindo as linhas restantes (o GNU sed não é compatível com POSIX em alguma condição, veja abaixo).
E continuando do documento:
Para arquivos não procuráveis, o estado do deslocamento do arquivo na descrição do arquivo aberto para esse arquivo não é especificado
Nesse caso, o comportamento não é especificado. A maioria das ferramentas padrão, include sed
, consumirá a entrada o máximo possível. Ele lê passar a yyy
linha e q
sair sem restaurar o deslocamento do arquivo, então não resta mais nada cat
.
O GNU sed
não é compatível com o padrão, depende da implementação stdio do sistema e da versão glibc:
$ (gsed '/y/ q'; echo aaa; cat) < test
xxx
yyy
aaa
Aqui, o resultado foi obtido no Mac OSX 10.11.6, máquinas virtuais Centos 7.2 - glibc 2.17, Ubuntu 14.04 - glibc 2.19, que são executadas no Openstack com back-end do CEPH.
Nesses sistemas, você pode usar a -u
opção para obter o comportamento padrão:
(gsed -u '/y/ q'; echo aaa; cat) </tmp/test
e para tubo:
$ cat test | (gsed -u '/y/ q'; echo aaa; cat)
xxx
yyy
aaa
zzz
o que leva a um desempenho terrivelmente ineficiente, porque sed
é necessário 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
...
cat
(no sub shell) pode reutilizar o descritor de arquivo no primeiro caso, porque stdin está vinculado a um arquivo real. No segundo caso, stdin é de um pipe e não de um arquivo real. Observe que também(sed '/y/ q'; echo aaa; cat) < <(cat test)
não imprimezzz
.