Respuestas:
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
-lopción para que ambos comandos se consideren iguales.
Tubería una grepen otra:
grep "string1" /path/to/files/* | grep "string2"
Aquí está el comando ack 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.
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.
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.
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.
-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 comoFILEargumento 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.