¿Cómo encontrar archivos que contienen dos cadenas juntas en Linux?

11

Quiero encontrar archivos que contengan dos cadenas juntas, por ejemplo, el archivo contiene ambos string1y string2.

Quiero la ruta completa de los archivos en la salida. No quiero ver advertencias de "permiso denegado".

alwbtc
fuente

Respuestas:

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

que es lo mismo que

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

Editar: heres por qué grep string1 /path/* | grep string2no hace lo que creo que alwbtc quiere.

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

No se encontró nada, pero el archivo b contiene ambas cadenas.

Esto es lo que creo que alwbtc quiere

$ grep -l apples $(grep -l mangoes /tmp/*)
/tmp/b
RedGrittyBrick
fuente
1
Esta es una solución ordenada y más útil que la mía. Para aquellos que quieran saber lo que está sucediendo aquí (me tomó un poco entender), está usando la -lopción de devolver los nombres de los archivos en lugar de las líneas. Luego usa el signo de dólar o las comillas inversas para pasar esa lista como FILEargumento al segundo grep. Esto permite que el segundo grep busque la totalidad de cada archivo encontrado en lugar de las líneas individuales como en mi solución.
embedded.kyle
Se perdió una -lopción para que ambos comandos se consideren iguales.
pong
2

Tubería una grepen otra:

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

Embedded.kyle
fuente
55
Si las dos cadenas están en líneas diferentes en el archivo, esto no funcionará.
RedGrittyBrick
1
No sabía que era un requisito para ellos estar en la misma línea @RedGrittyBrick
slhck
@slhck: He actualizado mi respuesta para mostrar lo que creo que alwbtc quiere y por qué esta respuesta no hace eso. Por supuesto, es posible que haya entendido mal lo que alwbtc quiere e incrustado. Kyle puede haberlo hecho bien, aunque sospecho que no.
RedGrittyBrick
1

Aquí está el comando equivalente a la respuesta de RedGrittyBrick :

ack string2 $(ack string1 -l)

Funciona de la misma manera (excepto ackpor defecto busca el directorio actual de forma recursiva). El contenido dentro de las $()búsquedas string1pero -lsolo genera los nombres de archivo donde se encontró esa cadena. Luego se pasan como argumentos al comando externo, lo que significa que solo string2se busca dentro de esa lista de archivos.

congusbongus
fuente
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)

o 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/*)

Esto funcionará si las cadenas están en diferentes líneas del mismo archivo y también evitará falsos positivos si un nombre de archivo contiene una de las cadenas.

usuario381521
fuente
0

Para profundizar en la solución de @ RedGrittyBrick que tiene una deficiencia al ejecutar el comando desatendido más para suprimir la salida de error según lo previsto y encontrar archivos de forma recursiva, puede considerar

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

-sLa opción suprimirá los mensajes de error. La
-ropción permite buscar cadenas en directorios anidados arbitrariamente
!combinados con && echo /dev/nullgarantías de que el comando no colgará. De lo contrario, si inner grepno encuentra ningún archivo, no generará nada, por lo que outer grepesperará indefinidamente la entrada para buscar. Este salidas solución /dev/nullen estos casos por lo que outer grepvan a buscar STRING1en /dev/nulldonde se supone que no encontrar nada.

apestar
fuente
0

Estaba buscando una forma extensible de hacer 2 o más cadenas y se me ocurrió esto:

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

La primera grep encuentra de forma recursiva los nombres de los archivos que contienen string1dentro path-to-files.

Los resultados se canalizan a los xargsque ejecuta uno o más comandos grep en esos archivos string2.

Los resultados se canalizan a otro xargscomando para string3: es el mismo que la primera xargsllamada, pero busca una cadena diferente.

El uso de xargsevitará problemas cuando haya tantos resultados que la línea de comando resultante del uso de ticks de retroceso sea demasiado larga.

Para evitar las advertencias podemos redirigir stderra /dev/null:

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

No es necesario en las siguientes llamadas grep porque string1ya se ha encontrado dentro del archivo, por lo que se sabe que los permisos son buenos.

Awatts
fuente