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

grep pattern1 | grep pattern2 | ... 

Entonces, ¿cómo convertirlo a algo como?

grep pattern1 & pattern2 & pattern3 

Me gustaría usar un solo grep porque estoy construyendo argumentos dinámicamente, así que todo tiene que caber en una sola cadena. El uso de filtro es una característica del sistema, no grep, por lo que no es un argumento para ello.


No confunda esta pregunta con:

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

Esta es una O coincidencia de múltiples patrones.

Comentarios

Responder

agrep puede hacerlo con esta sintaxis:

agrep "pattern1;pattern2" 

Con GNU grep, cuando se construye w ith compatibilidad con PCRE, puede hacer:

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

Con ast grep :

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

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

Si los patrones no se superponen, es posible que también pueda hacer:

grep -e "pattern1.*pattern2" -e "pattern2.*pattern1" 

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

awk "/pattern1/ && /pattern2/" 

Con sed:

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

Tenga en cuenta que todos estos tendrán una sintaxis de expresión regular diferente.

Comentarios

  • La sintaxis de agrep no funciona para yo … ¿en qué versión se introdujo?
  • @Raman 2.04 de 1992 ya lo tenía. Yo ‘ no tengo ninguna razón para creer que no estaba ‘ t allí desde el principio. Se pueden encontrar versiones más recientes (posteriores a 1992) de agrep incluidas con glimpse / webglimpse . Posiblemente tengas una implementación diferente. Sin embargo, tuve un error con la versión ast-grep, la opción para expresiones regulares aumentadas es -X, no -A.
  • @St é phaneChazelas Gracias, tengo agrep 0.8.0 en Fedora 23. Esto parece ser un agrep diferente al que hace referencia.
  • @Raman, el suyo suena como TRE agrep .
  • @Techiee, o simplemente awk '/p1/ && /p2/ {n++}; END {print 0+n}'

Respuesta

No especificaste la versión grep, esto es importante. Algunos motores de expresiones regulares permiten múltiples coincidencias agrupadas por Y usando «& «pero esta es una característica no estándar y no portátil. Pero, al menos GNU grep no es compatible con esto.

OTOH, simplemente puede reemplazar grep con sed, awk, perl, etc. . (enumerados en orden de aumento de peso). Con awk, el comando se vería como

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

y se puede construir para ser especificado en la línea de comandos de una manera fácil.

Comentarios

  • Solo recuerde que awk usa ‘ s ERE, p. ej. el equivalente de grep -E, a diferencia de los BRE ‘ que utiliza el grep simple.
  • awk ‘ s expresiones regulares son llamadas ERE, pero de hecho ‘ son un poco idiosincrásicos. Aquí hay probablemente más detalles de los que a nadie le importa: wiki.alpinelinux.org/wiki/Regex
  • Gracias, grep 2.7.3 ( openSUSE). Te voté, pero mantendré la pregunta abierta por un tiempo, tal vez haya algún truco para grep (no es que no me guste awk, simplemente saber más es mejor).
  • La acción predeterminada es imprimir la línea correspondiente para que la { print; } no sea ‘ realmente necesaria o útil aquí.

Respuesta

Si patterns 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 -  

O esto coincide con subcadenas en lugar de regular expresiones:

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

Para imprimir todo en lugar de ninguna línea de la entrada en el En caso de que patterns esté vacío, reemplace NR==FNR por FILENAME==ARGV[1] o por ARGIND==1 en gawk.

Estas funciones imprimen las líneas de STDIN que contienen cada cadena especificada como argumento como una subcadena. ga significa grep all y gai ignora mayúsculas y minúsculas.

 ga(){ awk "FILENAME==ARGV[1]{a[$0];next}{for(i in a)if(!index($0,i))next}1" <(printf %s\\n "[email protected]") -; } gai(){ awk "FILENAME==ARGV[1]{a[tolower($0)];next}{for(i in a)if(!index(tolower($0),i))next}1" <(printf %s\\n "[email protected]") -; }  

Comentarios

  • respuesta nítida que aborda varios casos de uso y trabajos (verificado en macos)

Respuesta

grep pattern1 | grep pattern2 | ...

Me gustaría usar un solo grep porque estoy construyendo argumentos dinámicamente , por lo que todo debe caber en una cadena

En realidad, es posible construir la canalización de forma dinámica (sin recurrir a eval):

 # Executes: grep "$1" | grep "$2" | grep "$3" | ... function chained-grep { local pattern="$1" if [[ -z "$pattern" ]]; then cat return fi shift grep -- "$pattern" | chained-grep "[email protected]" } cat something | chained-grep all patterns must match order but matter dont  

Sin embargo, probablemente no sea una solución muy eficiente.

Comentarios

  • Utilice chained-grep() o function chained-grep pero no function chained-grep(): unix.stackexchange.com/questions/73750/…
  • ¿Puedes describir cuál es el truco? ¿Puedes agregarlo a la respuesta ( sin » Editar: «, » Actualización: «, o similar) editándolo ?
  • Reformuló la respuesta para aclarar el truco (es decir, construir una tubería de shell dinámicamente)

Responder

git grep

Esta es la sintaxis con git grep combinando varios patrones usando expresiones booleanas :

git grep --no-index -e pattern1 --and -e pattern2 --and -e pattern3 

El comando anterior imprimirá líneas que coincidan con todos los patrones a la vez.

--no-index Buscar archivos en el directorio actual que no está administrado por Git.

Marque man git-grep para obtener ayuda.

Consulte también:

Para la operación OR , consulte:

Comentarios

  • Excelente respuesta. Gracias.

Respuesta

Aquí está mi opinión, y esto funciona para palabras en varias líneas:

Utilice find . -type f seguido de tantos
-exec grep -q "first_word" {} \;
y la última palabra clave con
-exec grep -l "nth_word" {} \;

-q silencioso / silencioso
-l mostrar archivos con coincidencias

La siguiente lista devuelve nombres de archivos con las palabras «conejo» y «agujero» en ellos:
find . -type f -exec grep -q "rabbit" {} \; -exec grep -l "hole" {} \;

Comentarios

  • Si miras con atención, es posible que descubras que esta no es la funcionalidad que solicita la pregunta.

Respuesta

ripgrep

Aquí está el ejemplo usando rg :

rg -N "(?P<p1>.*pattern1.*)(?P<p2>.*pattern2.*)(?P<p3>.*pattern3.*)" file.txt 

Es una de las herramientas de grepping más rápidas, ya que está construida sobre motor de expresiones regulares de Rust que utiliza autómatas finitos, SIMD y optimizaciones literales agresivas para hacer la búsqueda muy rápida.

Consulte también la solicitud de funciones relacionadas en GH-875 .

Respuesta

Para encontrar todas las palabras (o patrones), puede ejecutar grep en un for bucle. La principal ventaja aquí es buscar desde una lista de expresiones regulares .

Un ejemplo real:

# File "search_all_regex_and_error_if_missing.sh" find_list="\ ^a+$ \ ^b+$ \ ^h+$ \ ^d+$ \ " for item in $find_list; do if grep -E "$item" file_to_search_within.txt then echo "$item found in file." else echo "Error: $item not found in file. Exiting!" exit 1 fi done 

Ahora ejecutémoslo en este archivo:

hhhhhhhhhh aaaaaaa bbbbbbbbb ababbabaabbaaa ccccccc dsfsdf bbbb cccdd aa caa 
$ ./search_all_regex_and_error_if_missing.sh aaaaaaa aa ^a+$ found in file. bbbbbbbbb bbbb ^b+$ found in file. hhhhhhhhhh ^h+$ found in file. Error: ^d+$ not found in file. Exiting! 

Comentarios

  • Tu lógica es defectuosa: pedí ALL operador, su código funciona como OR operador, no AND. Y por cierto, para eso (OR) es una solución mucho más fácil dada en la pregunta.
  • @greenoldman La lógica es simple: el bucle for will en TODAS las palabras / patrones en la lista, y si se encuentra en el archivo, lo imprimirá. Así que simplemente elimine el else si no ‘ no necesita acción en caso de que no se encuentre la palabra.
  • Entiendo su lógica y mi pregunta. Estaba preguntando acerca del operador AND, lo que significa que el archivo es solo un resultado positivo si coincide con el patrón A y el patrón B y patrón C y … AND En su caso, el archivo es positivo si ma tches patrón A o patrón B o … ¿Ves la diferencia ahora?
  • @greenoldman no está seguro de por qué crees que este bucle no verifica Y condiciona todos los patrones? Entonces ‘ he editado mi respuesta con un ejemplo real: buscará en el archivo todas las expresiones regulares de la lista, y en la primera que falte, saldrá con un error.
  • Lo tiene justo delante de sus ojos, tiene una coincidencia positiva justo después de que se ejecuta la primera coincidencia. Debe tener » recopilar » todos los resultados y calcular AND en ellos. Luego, debería reescribir el script para que se ejecute en varios archivos; entonces tal vez se dé cuenta de que la pregunta ya está respondida y su intento no trae nada a la mesa, lo siento.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *