El grep anulado nested da como resultado una cadena que dice "(input estándar)"

Estoy realizando un grep nested como este:

grep -ir "Some string" . |grep "Another string I want to find in the other grep's results" 

Esto funciona perfectamente según lo previsto (obtengo los resultados del primer grep filtrado por el segundo grep también), pero tan pronto como agregue una opción "-l", solo obtengo la list de files del segundo grep, no get algo

 grep -ir "Some string" . |grep -l "Another string I want to find in the other grep's results" 

Esto da como resultado el siguiente resultado:

(salida estándar)

Supongo que las tuberías no funcionan cuando solo quiero la list de files. Alguna alternativa?

utilice "cortar" para eliminar cadenas después de ":" luego obtendrá partes de files (suponiendo que las routes de files no contienen dos puntos o caracteres de nueva línea y no coinciden con el segundo patrón).

 grep -ir "Some string" . |grep "Another string I want to find in the other grep's results" | cut -d ":" -f 1 

en caso de duplicaciones use "uniq"

 grep -ir "string1" . | grep "string2" | cut -d: -f1 | uniq 

La opción -l de grep hará que la utilidad imprima solo el nombre del file que contiene el patrón especificado. El manual en mi sistema dice lo siguiente acerca de esta opción:

Solo los nombres de los files que contienen las líneas seleccionadas se escriben en la salida estándar. grep solo searchá un file hasta que se encuentre una coincidencia, haciendo que las búsquedas sean potencialmente less costosas. Los nombres de las routes se enumeran una vez por cada file buscado. Si se busca la input estándar, se escribe la cadena "(input estándar)".

Dado que el segundo grep en su canalización está leyendo desde una input estándar, no desde un file, no sabe de dónde provienen los datos, aparte de que está llegando a su flujo de input estándar. Es por eso que devuelve la cadena de text (standard input) (no (standard output) como está escrito en la pregunta). Esto es lo más cerca que puede llegar al lugar donde se encuentra el partido.

Para combinar los dos patrones en el primer grep (que tiene conocimiento sobre qué files está buscando), consulte " ¿Cómo ejecutar grep con múltiples patrones Y? "

(Supongo que pretendía que el segundo grep coincidiera con el contenido de la línea y no con los nombres de los files o ambos, como lo hacía su enfoque)

POSIXly:

 find . -type f -exec awk ' FNR == 1 {found = 0} !found && tolower($0) ~ /some string/ && /other string/ { print FILENAME found = 1 nextfile }' {} + 

El negocio sobre found es para las implementaciones de awk que aún no son compatibles con el nextfile (y donde nextfile es entonces no nextfile ). Si sabe que su implementación de awk admite el nextfile , puede simplificarlo para:

  find . -type f -exec awk 'tolower($0) ~ /some string/ && /other string/ { print FILENAME; nextfile}' {} + 

Con GNU grep construido con soporte PCRE, ya que quiere que una coincidencia sea insensible a las mayúsculas y no a la otra:

 grep -rlP '^(?=.*(?i:some string))(?=.*other string)' . 

(?=...) es un operador de Perl Look -ahead . (?i:pattern) activa la coincidencia insensible a mayúsculas y minúsculas solo para el pattern . Así que aquí estamos haciendo una coincidencia al principio de la línea ( ^ ) siempre que vaya seguida de cualquier cantidad de caracteres ( .* ) Seguidos por some string (sin distinción entre mayúsculas y minúsculas) y también que (el principio de la línea) va seguido de cualquier número de caracteres y other string (sensible a mayúsculas y minúsculas).

Si su grep no es compatible con -P , puede tener el command pcregrep lugar (reemplace grep -rlP con pcregrep -rl ), o si los patrones no se superponen, puede hacer:

 grep -rl -e '[sS][oO][mM][eE] [sS][tT][rR][iI][nN][gG].*other string' \ -e 'other string.*[sS][oO][mM][eE] [sS][tT][rR][iI][nN][gG]' . 

O, si no le importan las dos coincidencias, no distingue entre mayúsculas y minúsculas:

 grep -ril -e 'some string.*other string' \ -e 'other string.*some string' . 

Puede colocar ambos patrones en una consulta (según esta respuesta ) utilizando el siguiente patrón:

 grep -P '^(?=.*pattern1)(?=.*pattern2)' 

En su caso, puede agregar los parameters -ir -l de la siguiente forma:

 grep -irlP '^(?=.*pattern1)(?=.*pattern2)' . 

Esta es la solución más corta de todas las proporcionadas.

 find . -type f -exec perl -lne ' /Some string/i and /other string/ and print($ARGV),close(*ARGV); ' {} + 

 grep -irZ "Some string" . | perl -lsF'/\n/' -0ne ' s/^/\n/ if $. == 1; s/$/\n/ if eof; $. == 1 and $prev = $F[1],next; push @{$h{$prev}}, $F[0]; $prev = $F[1]; END { grep($_ =~ /\Q${str2}/, @{$h{$_}}) and print for keys %h; } ' -- -str2="Another string" 

Principio de funcionamiento: Aquí el primer grep realiza una búsqueda recursive , case-insensitive de "alguna cadena" en el directory actual y hacia abajo, y genera loggings separados por nulo ( \0 ) debido a la opción -Z dada a grep .

Cada uno de estos loggings contiene el nombre de file y la línea que coinciden. El único inconveniente es que el order no está en el paso, debido al comportamiento de grep de no poner un \0 después de la línea coincidente. Para evitar esta limitación, hacemos uso de Perl leyendo loggings separados por nulo y dividiendo estos loggings en \n para separar las líneas de los nombres de file.

Por lo tanto, no hay ninguna limitación en los types de nombres de files que pueden estar involucrados, con la exception de \0 , que de todos modos están prohibidos.