Grep apenas a primeira partida e pare

329

Estou pesquisando um diretório recursivamente usando grep com os seguintes argumentos na esperança de retornar apenas a primeira correspondência. Infelizmente, ele retorna mais de um - na verdade, dois da última vez que olhei. Parece que tenho muitos argumentos, especialmente sem obter o resultado desejado. : - /

# grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/directory

retorna:

Pulsanti Operietur
Pulsanti Operietur

Talvez grep não seja a melhor maneira de fazer isso? Você me diz, muito obrigado.

Tim Kamm
fonte

Respostas:

512

-m 1significa retornar a primeira correspondência em qualquer arquivo. Mas ainda continuará pesquisando em outros arquivos. Além disso, se houver duas ou mais correspondências na mesma linha, todas elas serão exibidas.

Você pode usar head -1para resolver este problema:

grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/dir | head -1

explicação de cada opção grep:

-o, --only-matching, print only the matched part of the line (instead of the entire line)
-a, --text, process a binary file as if it were text
-m 1, --max-count, stop reading a file after 1 matching line
-h, --no-filename, suppress the prefixing of file names on output
-r, --recursive, read all files under a directory recursively
mvp
fonte
impressionante! obrigado. btw - são todos esses outros argumentos necessários que eu tenho no comando? e se eu não conseguir canalizá-lo por acaso (apenas no caso).
precisa
2
Eu não acho que eles são necessários (exceto -robviamente), mas não devem doer (eu não usaria -a)
mvp
3
Exatamente o que eu precisava. Meu padrão foi encontrado duas vezes na mesma linha e grep -m 1retornou as duas instâncias por causa disso. |head -1Resolvi-o!
harperville
6
@Chris_Rands, o comportamento exato depende do shell em que você está executando. O head sai assim que encontra a primeira linha. O grep será encerrado na próxima vez que tentar gravar após a saída do head. Algumas conchas aguardam até que todos os elementos de um oleoduto sejam concluídos, outras farão com que todo o tubo seja desligado assim que o último programa no tubo sair.
puhlen
1
@ 3Qn, eu não entendo o seu comentário: first not first from result. Esta resposta imprime a primeira correspondência em qualquer arquivo e para. O que mais você esperava?
mvp
31

Você pode canalizar o grepresultado headem conjunto com o stdbuf .

Observe que, para garantir a parada após a enésima correspondência, você precisa usar stdbufpara garantir grepque a saída não seja armazenada em buffer:

stdbuf -oL grep -rl 'pattern' * | head -n1
stdbuf -oL grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/dir | head -n1
stdbuf -oL grep -nH -m 1 -R "django.conf.urls.defaults" * | head -n1

Assim que headconsome 1 linha, ele é finalizado e grepreceberá SIGPIPEporque ainda gera algo para canalizar enquanto headestava fora.

Isso assumiu que nenhum nome de arquivo contém nova linha.

Venkat Kotra
fonte
Eu estou tentando adotar esta solução de pesquisa em um grande número de arquivos de arquivo com xargs: find . -name '*.gz' | xargs -I '{}' stdbuf -oL zgrep -al 'pattern' {} | head -n 1. Isso, no entanto, não termina na primeira partida. Algum conselho?
DKroot
1
Não grep's --line-bufferedopção Evitar tampão sobrecarga sem chamar um utilitário adicional?
David
23

Meu programa grep-like acktem uma -1opção que para na primeira partida encontrada em qualquer lugar. Ele suporta o -m 1que @mvp também se refere. Eu o coloquei lá porque, se estou pesquisando uma grande árvore de código-fonte para encontrar algo que sei que existe em apenas um arquivo, é desnecessário encontrá-lo e preciso pressionar Ctrl-C.

Andy Lester
fonte
então você diria que ack é mais rápido que grep? Estou realmente preocupado com o fator de velocidade também.
precisa
1
O ack pode ser mais rápido que o grep, dependendo do que você está pesquisando. Observe que ack é sobre a busca de código fonte. Se você deseja pesquisar arquivos gerais, é menos bom nisso, pelo menos no ack 1.x. Leia sobre ack e veja se ele atende às suas necessidades.
Andy Lester
2
Eu tenho usado Ack por um longo tempo, mas recentemente mudou para O pesquisador prata que eu acho que ser mais rápido do Ack
guy.gc
Eu acredito que essa deve ser a única resposta, porque o OP disse que queria que ele fosse feito com grep, mas a outra resposta usa head (ambos funcionam, é claro), mas existem alguns ambientes incorporados / criados por você com ferramentas mínimas em que grep é comum e tail / cabeça não é.
Areeb Soo Yasir
Vale ressaltar que agpode ser rápido, mas não tem a -1opção que é útil neste caso
jja 14/04
4

Você pode usar o comando abaixo se desejar imprimir uma linha inteira e o nome do arquivo se a ocorrência de uma palavra específica no diretório atual estiver sendo pesquisada.

grep -m 1 -r "Not caching" * | head -1
Gaurav londhe
fonte
2

Um único revestimento, usando find:

find -type f -exec grep -lm1 "PATTERN" {} \; -a -quit
Yam Marcovic
fonte
6
Isso será muito lento, pois o find gerará cópia do grep para cada arquivo encontrado. grep -rfunciona muito mais rápido - é a única cópia que faz travessias de diretório.
Mvp
Verdade; embora o find possa ser personalizado para operar apenas com resultados filtrados, o que pode tornar a operação muito mais rápida do que um grep abrangente. Depende do contexto.
Yam Marcovic