Comentários
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 primeirogrep
para tornar a solução GNU recursiva para mim, em vez de usar a linha POSIX com todos aquelesexec
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 porquegrep -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
egrep -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 é ' tfor 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 *
Masfor 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)
321
em vez debar
: – D