Esta pergunta já tem respostas aqui :

Comentários

  • O que você quer dizer por " a parte inteira de cada string "? Você não ' quer que a linha inteira seja impressa?
  • Você pode confirmar que deseja que os arquivos correspondentes contenham " foo " e " 321 ", mas não apenas " foo " ou apenas " 321 "?
  • Gosto de como ' s 321 em vez de bar: – D

Resposta

GNU grep

Deve ser um pouco mais rápido porque o segundo grep pode operar em uma lista de arquivos.

grep -lZ "foo" * | xargs -0 grep -l "321" 

POSIX grep com find

find é mais útil se você quiser pesquisar diretórios recursivos (nesse caso, perder -mindepth e -maxdepth opções.

find . -mindepth 1 -maxdepth 1 -type f -exec grep -q "foo" {} \; -exec grep -l "321" {} + 

Comentários

  • -r funcionou bem no primeiro grep para tornar a solução GNU recursiva para mim, em vez de usar a linha POSIX com todos aqueles exec s

Resposta

Você pode fazer isso com um pequeno script:

for FILE in * do grep -q foo $FILE && grep -q 321 $FILE && echo $FILE done 

Você também pode fazer isso em uma linha:

for FILE in *; do grep -q foo $FILE && grep -q 321 $FILE && echo $FILE; done 

grep retorna 0 (verdadeiro) se encontrou a string e a && separando os comandos significa que o segundo só será executado se o primeiro for verdadeiro. A opção -q garante que grep não produza nada.

O eco só será executado se ambas as strings forem encontrado no mesmo arquivo.


Pensei em uma maneira diferente de fazer isso. Desta forma, provavelmente será mais eficiente se os arquivos em questão forem maiores do que a RAM instalada, pois só precisa grep passar por cada arquivo uma vez.

 for FILE in * do test $(egrep -o "foo|321" $FILE | uniq | sort | uniq | wc -l) -eq 2 && echo $FILE done 

e a versão de uma linha:

 for FILE in *; do test $(egrep -o "foo|321" $FILE | uniq | sort | uniq | wc -l) -eq 2 && echo $FILE; done 

Comentários

  • Para uma solução mais eficiente: e se o arquivo tiver " foo foo " nele?
  • Isso ' é para que serve uniq | sort | uniq. " foo foo " acaba sendo uma linha, mas " foo 321 " acaba sendo duas linhas porque grep -o produz todas as strings encontradas em linhas separadas, mesmo se elas começarem na mesma linha.
  • Se os arquivos ficarem tão grandes a ponto de não haver problemas em bifurcar pelo menos seis vezes por arquivo, provavelmente faz sentido usar o awk para que os arquivos não precisem ser pesquisados até o fim.
  • @Ladadadada obteve isto. 🙂
  • @HaukeLaging grep -q e grep -l não pesquisa até o final do arquivo: eles saem logo como uma correspondência é encontrada. Isso me faz pensar por que a primeira solução não é ' t for FILE in *; do grep -q foo "$FILE" && grep -l 321 "$FILE"; done

Resposta

Estranho. Para mim, ambas as variantes funcionam (grep (GNU grep) 2.13):

grep "foo\|321" grep -E "foo|321" 

Editar 1 – mostrar arquivos com ambas as correspondências apenas

A for file in * resposta funciona, mas pode se tornar um pesadelo de desempenho (para grandes quantidades de arquivos ): pelo menos dois processos por arquivo. Isso é mais rápido (no mundo GNU):

find . -type f -print0 | xargs -0 -r grep --files-with-matches --null -- string1 | xargs -0 -r grep --files-with-matches -- string2 

string1 deve ser aquela que resulta em menos correspondências.

Comentários

  • O autor da pergunta está procurando o resultado para retornar verdadeiro somente se um arquivo contiver ambas as strings, em vez de apenas corresponder a pelo menos uma.
  • Eu gosto disso opção --files-with-matches. Apenas leia sobre isso na página de manual e isso faz com que o grep pare após encontrar a primeira correspondência, o que significa que ' é muito eficiente para arquivos grandes se a correspondência ocorrer antes. Também diz que a opção curta -l é especificada por POSIX, para que possa ser usada fora do mundo GNU.
  • @Ladadadada A eficiência não é nenhuma vantagem sobre o seu -q, no entanto. Mencionando GNU, eu não estava ' pensando em –files-with-match, mas em -0 / –null.O que me vem à mente: a expansão do nome do caminho contém classificação alfabética (muito ruim: parece que não pode ' ser desativado), portanto, para grandes quantidades de arquivos, até mesmo seu for file in * realmente para de ser divertido.
  • Na verdade, as otimizações de eficiência seriam bem diferentes para alguns arquivos grandes em comparação com muitos pequenos e * simplesmente ' não funcionará depois de alguns milhares de arquivos.
  • @Ladadadada Não ' t funciona como parte de uma linha de comando para um comando externo: grep foo * Mas for file in * é uma estrutura interna do shell, então eu assumiria que o limite da linha de comando não é aplicável aqui.

Resposta

Basicamente, para localizar todos os arquivos, incluindo um determinado string em um diretório, você pode usar:

grep -lir "pattern" /path/to/the/dir 
  • -l: para fazer esta verificação irá parar na primeira correspondência
  • -i: para ignorar as distinções de maiúsculas e minúsculas nos arquivos de padrão e de entrada
  • -r: pesquisa todos os arquivos no diretório, recursivamente

Para pesquisar dois padrões, tente isto:

grep -lr "321" $(grep -lr "foo" /path/to/the/dir) 

Comentários

  • Comentários chatos padrão sobre $() não lidar com espaços são aplicáveis. Na prática, para um liners no shell, este comando funcionará bem.

Resposta

Deve ser

grep -e "foo" -e "321" * 

Use -e para vários padrões

EDIT

No caso de você precisar que os dois correspondam:

grep -e ".*foo.*321.*" * 

Se a ordem não importa:

grep -e ".*foo.*321.*" ".*321.*foo.*" * 

Comentários

  • Isso não fornece uma resposta para a pergunta. Para criticar ou solicitar esclarecimentos de um autor, deixe um comentário abaixo de sua postagem.
  • @mdpc Acho que fornece uma resposta. O que o faz pensar diferente?
  • @HaukeLaging Porque retorna se um dos padrões corresponder. O OP está procurando por um caso em que só retorna verdadeiro se ambos forem encontrados no arquivo.
  • Pelo que entendi, isso só encontra arquivos onde as duas strings contêm na mesma linha (I não ' pense. corresponde a novas linhas por padrão)

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *