Criei um arquivo de teste chamado 'test' que contém o seguinte:
xxx
yyy
zzz
Eu executei o comando:
(sed '/y/ q'; echo aaa; cat) < test
e eu tenho:
xxx
yyy
aaa
zzz
Então eu corri:
cat test | (sed '/y/ q'; echo aaa; cat)
e pegou:
xxx
yyy
aaa
Questão
sed
lê e imprime até encontrar uma linha com 'y' e depois para. No primeiro caso, mas não no segundo, o gato lê e imprime o resto.
Alguém pode explicar que fenômeno está por trás dessa diferença de comportamento?
Também notei que funciona dessa maneira no Ubuntu 16.04 e Centos 6, mas no Centos 7 nenhum comando imprime 'zzz'.
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
.(head -n1; head -n1) < test
ecat test | (head -n1; head -n1)
Respostas:
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:
Então em:
sed
executou oq
comando uit antes de atingir o EOF, deixando o deslocamento do arquivo no início dazzz
linha, paracat
continuar imprimindo as linhas restantes (o GNU sed não é compatível com POSIX em alguma condição, veja abaixo).E continuando do documento:
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 ayyy
linha eq
sair sem restaurar o deslocamento do arquivo, então não resta mais nadacat
.O GNU
sed
não é compatível com o padrão, depende da implementação stdio do sistema e da versão glibc: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:e para tubo:
o que leva a um desempenho terrivelmente ineficiente, porque
sed
é necessário ler um byte de cada vez. Uma saída parcial destrace
:fonte
sed
, isso depende da implementação do stdio do sistema. Nos sistemas GNU (com o GNU libc), o GNUsed
será compatível, assim como osexit()
arquivos gerenciados pelo stdio.sed
não for compatível, o meu laptop Manjaro faz, todos têm a mesmased
versão 4.2.2strace -f sh -c '{ sed "/y/q"; echo aaa; cat; } <test'
mostre que nãolseek()
foi realizado, enquanto no meu manjaro alseek()
foi chamado antesexit_group()
.main() { char buf[999]; gets(buf); }'
programa.