¿Cómo ejecutar grep con múltiples patrones AND?

Me gustaría get la coincidencia de múltiples patrones con AND implícito entre patrones, es decir, equivalente a ejecutar varios greps en una secuencia:

grep pattern1 | grep pattern2 | ... 

Entonces, ¿cómo convertirlo a algo así?

 grep pattern1 & pattern2 & pattern3 

Me gustaría usar grep único porque estoy construyendo arguments dinámicamente, por lo que todo tiene que caber en una cadena. Usar filter es una característica del sistema, no grep, por lo que no es un argumento para ello.


No confundas esta pregunta con:

 grep "pattern1\|pattern2\|..." 

Esta es una coincidencia de múltiples patrones O

Solutions Collecting From Web of "¿Cómo ejecutar grep con múltiples patrones AND?"

agrep puede hacerlo con esta syntax:

 agrep 'pattern1;pattern2' 

Con GNU grep , cuando se construye con soporte PCRE, puede hacer:

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

Con ast grep :

 grep -X '.*pattern1.*&.*pattern2.*' 

(sumr .* s como <x>&<y> coincide con cadenas que coinciden exactamente con <x> y <y> , a&b nunca coincidiría ya que no existe una cadena que pueda ser tanto b al mismo time).

Si los patrones no se superponen, también puede hacer:

 grep -e 'pattern1.*pattern2' -e 'pattern2.*pattern1' 

La mejor manera portátil es probablemente con awk como ya se mencionó:

 awk '/pattern1/ && /pattern2/' 

Con sed :

 sed -e '/pattern1/!d' -e '/pattern2/!d' 

Tenga en count que todos tendrán una syntax de expresión regular diferente.

No especificó la versión grep, esto es importante. Algunos motores regexp permiten la agrupación múltiple agrupada por AND usando '&', pero esta característica no es estándar y no es portátil. Pero, al less GNU grep no es compatible con esto.

OTOH puede simplemente replace grep con sed, awk, perl, etc. (enumerados en order ascendente de peso). Con awk, el command se vería como

 awk '/ regexp1 / && / regexp2 / && / regexp3 / {print;  } '

y puede ser construido para ser especificado en la línea de command de manera fácil.

Si patterns.txt contiene un patrón por línea, puede hacer algo como esto:

 awk 'NR==FNR{a[$0];next}{for(i in a)if($0!~i)next}1' patterns.txt - 

Para search cadenas fijas en lugar de expresiones regulares, use esta variante:

 awk 'NR==FNR{a[$0];next}{for(i in a)if(!index($0,i))next}1' patterns.txt - 

Para imprimir todo en lugar de no líneas de la input en el caso de que patterns.txt esté vacío, reemplace NR==FNR con FILENAME==ARGV[1] o con ARGIND==1 en gawk .

Esta no es una solución muy buena, pero ilustra un "truco" bastante genial

 function chained-grep() { local pattern="$1" if [[ -z "$pattern" ]]; then cat return fi shift grep -- "$pattern" | chained-grep "$@" } cat something | chained-grep all patterns must match order but matter dont 

Este command de shell puede ayudar:

 eval "</dev/stdin $(printf "|grep '%s'" pattern1 pattern2)" FILE 

Sin embargo, es más fácil si todos sus patrones se almacenan en el file, por lo que puede definir el siguiente alias:

 alias grep-all="cat $(xargs printf '| grep "%s"' < patterns.txt)" 

y usarlo como:

 cat text.txt | grep-all 

Por supuesto, puede modificar el alias dependiendo de la syntax requerida, así que con este alias:

 alias grep-all="</dev/stdin $(xargs printf '|grep "%s"' < patterns.txt)" 

puedes usar solo un command, por ejemplo

 grep-all text.txt 

Para get más ideas, compruebe también: haga coincidir todos los patrones del file a la vez .

Todavía puedes usar egrep

  egrep "patern1|patern2" file