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 unagrep
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 degrep -E
, a diferencia de los BRE ‘ que utiliza elgrep
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 "$@") -; } gai(){ awk "FILENAME==ARGV[1]{a[tolower($0)];next}{for(i in a)if(!index(tolower($0),i))next}1" <(printf %s\\n "$@") -; }
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 "$@" } 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()
ofunction chained-grep
pero nofunction 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:
- Cómo nosotros e grep para que coincida con string1 AND string2?
- Verifique si todas las cadenas múltiples o expresiones regulares existen en un archivo .
Para la operación OR , consulte:
- ¿Cómo hago grep para múltiples patrones con patrón que tiene un carácter de tubería?
- Grep: cómo agregar un » O » condición?
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 comoOR
operador, noAND
. 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.
foo
y líneas que contenganbar
» ver usar grep para múltiples patrones de búsqueda