Como encontrar arquivos contendo duas strings juntas no Linux?

11

Quero encontrar arquivos que contenham duas cadeias juntos, por exemplo, o arquivo contém ambos string1e string2.

Eu quero o caminho completo dos arquivos na saída. Não quero ver avisos de "permissão negada".

alwbtc
fonte

Respostas:

15
grep -l string2 `grep -l string1 /path/*`

que é o mesmo que

grep -l string2 $(grep -l string1 /path/*)

Edit: aqui está porque grep string1 /path/* | grep string2não faz o que eu acho que alwbtc.

$ cd /tmp
$ cat a
apples
oranges
bananas
$ cat b
apples
mangoes
lemons
$ cat c
mangoes
limes
pears
$ cd ~
$ grep apples /tmp/* | grep mangoes
$

Nada foi encontrado, mas o arquivo b contém as duas strings.

Aqui está o que eu acho que o alwbtc quer

$ grep -l apples $(grep -l mangoes /tmp/*)
/tmp/b
RedGrittyBrick
fonte
11
Esta é uma solução elegante e mais útil que a minha. Para aqueles que querem saber o que está acontecendo aqui (demorei um pouco para descobrir), ele está usando a -lopção de retornar os nomes dos arquivos em vez das linhas. Ele está usando o cifrão ou as aspas para passar essa lista como FILEargumento para o segundo grep. Isso permite que o segundo grep pesquise a totalidade de cada arquivo encontrado, em vez das linhas individuais, como na minha solução.
embedded.kyle
Você perdeu uma -lopção para os dois comandos serem considerados iguais.
pong
2

Coloque um grepno outro:

grep "string1" /path/to/files/* | grep "string2"

Embedded.kyle
fonte
5
Se as duas strings estiverem em linhas diferentes no arquivo, isso não funcionará.
RedGrittyBrick
11
Eu não sabia que havia um requisito para que eles estivessem na mesma linha @RedGrittyBrick
slhck
@ slhck: Atualizei minha resposta para mostrar o que eu acho que o alwbtc quer e por que essa resposta não faz isso. Claro, eu posso ter entendido mal o que sempre quer e incorporado. Kyle pode ter acertado - eu suspeito que não.
RedGrittyBrick
1

Aqui está o comando equivalente à resposta do RedGrittyBrick :

ack string2 $(ack string1 -l)

Funciona da mesma maneira (exceto, ackpor padrão, pesquisa o diretório atual recursivamente). O conteúdo nas $()pesquisas, string1mas -lgera apenas os nomes de arquivos em que essa sequência foi encontrada. Eles são passados ​​como argumentos para o comando externo, o que significa que string2é pesquisado apenas dentro dessa lista de arquivos.

congusbongus
fonte
0
comm -12 <(grep --fixed-strings --files-with-matches "STRING1" /path/to/files/* 2>/dev/null | sort) <(grep --fixed-strings --files-with-matches "STRING1" /path/to/files/* 2>/dev/null | sort)

ou menos redundante:

search_files () { str="$1"; shift; grep -Fl "$str" "$@" 2>/dev/null | sort; }
comm -12 <(search_files "STRING1" /path/to/files/*) <(sf "STRING2" /path/to/files/*)

Isso funcionará se as strings estiverem em linhas diferentes do mesmo arquivo e também evitará falsos positivos se um nome de arquivo contiver uma das strings.

user381521
fonte
0

Para elaborar a solução do @ RedGrittyBrick, que apresenta uma falha ao executar o comando autônomo, além de suprimir a saída de erro conforme o esperado e encontrar arquivos recursivamente, você pode considerar

grep -l 'STRING1' $(! grep -lrs 'STRING2' /absolute/path/to/search/dir && echo /dev/null)

-sA opção suprimirá as mensagens de erro. A
-ropção permite procurar seqüências de caracteres em diretórios aninhados arbitrariamente,
!combinadas com && echo /dev/nullgarantias de que o comando não será desligado. Caso contrário, se inner grepnão encontrar nenhum arquivo, ele não produzirá nada, de modo que outer grepaguardará indefinidamente a entrada para pesquisar. Esta solução saídas /dev/nullnestes casos assim outer grepvai procurar STRING1em /dev/nullonde é suposto para não encontrar nada.

pong
fonte
0

Eu estava procurando por uma maneira extensível de executar 2 ou mais strings e surgiu com isso:

grep -rl string1 path-to-files | xargs grep -l string2 | xargs grep -l string3

O primeiro grep encontra recursivamente os nomes dos arquivos que contêm string1dentro path-to-files.

Os resultados são canalizados para os xargsquais executa um ou mais comandos grep nesses arquivos string2.

Os resultados são então canalizados para outro xargscomando string3- é o mesmo que a primeira xargschamada, mas procurando uma sequência diferente.

O uso de xargsevitará problemas onde existem tantos resultados que a linha de comando resultante do uso de back-ticks é muito longa.

Para evitar os avisos, podemos redirecionar stderrpara /dev/null:

grep -rl string1 path-to-files  2>/dev/null | xargs grep -l string2

Não é necessário nas chamadas grep subsequentes, porque string1já foi encontrado dentro do arquivo, portanto, as permissões são boas.

awatts
fonte