Por que o 'grep -q' consome todo o arquivo de entrada?

22

Considere o seguinte arquivo de entrada:

1
2
3
4

Rodando

{ grep -q 2; cat; } < infile

não imprime nada. Eu esperaria que fosse impresso

3
4

Eu posso obter a saída esperada se eu alterá-la para

{ sed -n 2q; cat; } < infile

Por que o primeiro comando não imprime a saída esperada?
É um arquivo de entrada pesquisável e de acordo com o padrão sob OPTIONS :

-q
      Quiet. Nothing shall be written to the standard output, regardless of 
      matching lines. Exit with zero status if an input line is selected.

e mais abaixo, em UTILIZAÇÃO DO APLICATIVO (enfatize a minha):

The -q option provides a means of easily determining whether or not a pattern (or string) exists in a group of files. When searching several files, it provides a performance improvement (because it can quit as soon as it finds the first match)[...]

Agora, pelo mesmo padrão (em Introdução , em INPUT FILES )

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[...]

tail -n +2 file
(sed -n 1q; cat) < file
...

The second command is equivalent to the first only when the file is seekable.

Por que grep -q consome o arquivo inteiro?

Isso é gnu grep se for importante (apesar de Kusalananda apenas confirmar que o mesmo acontece no OpenBSD)

    
por don_crissti 25.01.2017 / 15:15

3 respostas

36

grep pára cedo, mas armazena sua entrada para que seu teste seja muito curto (e, sim, percebo que meu teste é imperfeito, já que não é pesquisável):

seq 1 10000 | (grep -q 2; cat)

começa em 6776 no meu sistema. Isso corresponde ao o buffer de 32 KiB usado por padrão no GNU grep:

seq 1 6775 | wc

saídas

   6775    6775   32768

Observe que o POSIX menciona somente melhorias de desempenho

When searching several files

Isso não gera nenhuma expectativa de melhorias de desempenho devido à leitura parcial de um único arquivo.

    
por 25.01.2017 / 15:23
2

Isto é obviamente devido ao buffer que grep faz para acelerar as coisas. Existem ferramentas que são projetadas especificamente para ler quantos caracteres forem solicitados e não mais. Um deles é expect :

{ expect -c "log_user 0; expect 2"; cat; } < infile

Eu não tenho um sistema para experimentar, mas acredito que expect vai comer tudo até encontrar a string esperada ( 2 ), e então terminar, deixando o resto da entrada para cat .

    
por 26.01.2017 / 11:30
1

Você está confundindo sed e grep.

Para o comando sed, -2q está dizendo para sair da iteração atual se na segunda linha, a opção -n estiver dizendo para funcionar silenciosamente, então você obterá todas as linhas após a segunda.

O comando grep é executado por padrão para gerar todas as linhas correspondentes - mas a opção -q diz para não produzir nada para o stdout. então, se a entrada contiver um "2", terá um valor de saída de SUCESSO, caso contrário, FALHA. O que eles são depende do seu sistema operacional e shell. Então, normalmente você diria se uma linha corresponde examinando o valor de saída do processo do grep. Isso é útil em um pipeline no qual você deseja saber se sua entrada contém algum valor como teste. Por exemplo,

if grep -q 'crash' <somelog.log ; then report_crash_via_email ; fi

Neste caso, não nos importamos em ver todas as linhas correspondentes, apenas nos preocupamos se pelo menos uma existe. O report_crash_via_email process / function pode então sair e reabrir o arquivo, ou não.

Se você quiser que o seu processo do grep pare depois que ele encontrar o caractere "2" - ele não irá, por padrão, inspecionar cada linha procurando ver se combina - você precisa dizer para fazer isso. O comutador de linha de comando para isso é -m <value> . Então, para o seu caso, grep -q -m1 2 .

    
por 25.01.2017 / 17:15

Tags