pattern - regex positive lookahead example
Regex lookahead para ''no seguido por'' en grep (6)
Estoy intentando grep para todas las instancias de Ui/.
no seguido por Line
o incluso solo por la letra L
¿Cuál es la forma correcta de escribir una expresión regular para encontrar todas las instancias de una cadena particular NO seguida de otra cadena?
Usando lookaheads
grep "Ui/.(?!L)" *
bash: !L: event not found
grep "Ui/.(?!(Line))" *
nothing
Creo que este enlace puede ayudarte, primero a entender cómo funciona la expresión regular y, en segundo lugar, cómo construir tu expresión regular: http://www.regular-expressions.info/tutorialcnt.html
Es probable que no pueda ejecutar lookaheads negativos estándar usando grep, pero generalmente debería poder obtener un comportamiento equivalente usando el interruptor "inverso" ''-v''. Usando eso puedes construir una expresión regular para el complemento de lo que quieres unir y luego canalizarlo a través de 2 greps.
Para la expresión regular en cuestión, podrías hacer algo como
grep ''Ui/.'' * | grep -v ''Ui/.L''
La búsqueda negativa, que es lo que buscas, requiere una herramienta más poderosa que la grep
estándar. Necesita un grep habilitado para PCRE.
Si tiene GNU grep
, la versión actual admite las opciones -P
o --perl-regexp
y luego puede usar la expresión regular que desea.
Si no tiene (una versión suficientemente reciente de) GNU grep
, entonces considere obtener ack
.
La respuesta a parte de su problema está aquí, y ack se comportaría de la misma manera: Ack y lookahead negativo dando errores
Está utilizando comillas dobles para grep, que le permite a bash "interpretar !
Como comando expandir historial".
Necesita envolver su patrón en SOLICITANTES: grep ''Ui/.(?!L)'' *
Sin embargo, vea la respuesta de @JonathanLeffler para abordar los problemas con lookaheads negativos en grep
estándar.
Si necesita utilizar una implementación de expresiones regulares que no admita lookaheads negativos y no le molesta emparejar caracteres adicionales *, entonces puede usar clases de caracteres negados [^L]
, alternancia |
y el final del anclaje de cadena $
.
En su caso grep ''Ui/./([^L]/|$/)'' *
hace el trabajo.
Ui/.
coincide con la cadena que le interesa/([^L]/|$/)
coincide con cualquier carácter que no seaL
o coincide con el final de la línea:[^L]
o$
.
Si desea excluir más de un solo carácter, solo necesita arrojar más alternancia y negación. Para encontrar a
no seguido por bc
:
grep ''a/(/([^b]/|$/)/|/(b/([^c]/|$/)/)/)'' *
Que es ( a
seguido de no b
o seguido por el final de la línea: a
luego [^b]
o $
) o ( a
seguido de b
seguido por no c
o seguido por el final de la línea: a
luego b
, luego [^c]
o $
.
Este tipo de expresión se vuelve bastante difícil de manejar y propensa a errores incluso con una cadena corta. Podría escribir algo para generar las expresiones, pero probablemente sería más fácil usar una implementación de expresiones regulares que admita lookaheads negativos.
* Si su implementación es compatible con grupos que no capturan, puede evitar la captura de caracteres adicionales.
Si su grep no es compatible con -P o --perl-regexp, y puede instalar grep habilitado para PCRE, p. Ej. "Pcregrep", entonces no necesitará ninguna opción de línea de comandos como GNU grep para aceptar regular compatible con Perl expresiones, solo corres
pcregrep "Ui/.(?!Line)"
No necesita otro grupo anidado para "Línea" como en su ejemplo "Ui. (?! (Línea))" - el grupo externo es suficiente, como he mostrado anteriormente.
Permíteme darte otro ejemplo de buscar aserciones negativas: cuando tienes una lista de líneas, devuelta por "ipset", cada línea muestra el número de paquetes en la mitad de la línea, y no necesitas líneas con cero paquetes, solo correr:
ipset list | pcregrep "packets(?! 0 )"
Si te gustan las expresiones regulares perl-compatibles y tienes perl pero no tienes pcregrep o tu grep no admite --perl-regexp, puedes usar scripts de una línea Perl que funcionan de la misma manera que grep:
perl -e "while (<>) {if (/Ui/.(?!Lines)/){print;};}"
Perl acepta stdin de la misma manera que grep, por ejemplo
ipset list | perl -e "while (<>) {if (/packets(?! 0 )/){print;};}"