Bash Regex avanzado con ejemplos

Bash Regex avanzado con ejemplos

Usando el poder de las expresiones regulares, se puede analizar y transformar documentos y cuerdas basados ​​en textual. Este artículo es para usuarios avanzados, que ya están familiarizados con las expresiones regulares básicas en Bash. Para obtener una introducción a las expresiones regulares bash, consulte nuestras expresiones regulares de Bash para principiantes con un artículo de ejemplos. Otro artículo que puede encontrar interesante son expresiones regulares en Python.

Listo para comenzar? Bucear y aprender a usar regexps como un profesional!

En este tutorial aprenderás:

  • Cómo evitar pequeñas diferencias del sistema operativo al afectar sus expresiones regulares
  • Cómo evitar usar patrones de búsqueda de expresión regulares demasiado genéricos como .*
  • Cómo emplear o no emplear sintaxis de expresión regular extendida
  • Ejemplos de uso avanzado de expresiones regulares complejas en Bash
Bash Regex avanzado con ejemplos

Requisitos y convenciones de software utilizados

Requisitos de software y convenciones de línea de comandos de Linux
Categoría Requisitos, convenciones o versión de software utilizada
Sistema Independiente de la distribución de Linux
Software Línea de comando bash, sistema basado en Linux
Otro La utilidad SED se utiliza como una herramienta de ejemplo para emplear expresiones regulares
Convenciones # - requiere que los comandos de Linux dados se ejecuten con privilegios raíz directamente como un usuario raíz o mediante el uso de sudo dominio
$-Requiere que los comandos de Linux dados se ejecuten como un usuario regular no privilegiado

Ejemplo 1: se dirige a usar expresiones regulares extendidas

Para este tutorial, utilizaremos SED como nuestro principal motor de procesamiento de expresión regular. Cualquier ejemplo dado generalmente se puede portar directamente a otros motores, como los motores de expresión regulares incluidos en GREP, AWK, etc.

Una cosa a tener en cuenta siempre cuando se trabaja con expresiones regulares, es que algunos motores regex (como el de SED) admiten la sintaxis de expresión regular regular y regular. Por ejemplo, SED le permitirá usar el -mi Opción (opción taquigrafía para --regexp-extendido), lo que le permite usar expresiones regulares extendidas en el script SED.

Prácticamente, esto da como resultado pequeñas diferencias en los modismos de sintaxis de expresión regular al escribir scripts de expresión regulares. Veamos un ejemplo:

$ echo 'muestra' | sed 's | [a-e] \+| _ | g' s_mpl_ $ echo 'muestra' | sed 's | [a-e]+| _ | g' muestra $ echo 'muestra+' | sed 's | [a-e]+| _ | g' sampl_ $ echo 'muestra' | sed -e 's | [a -e]+| _ | g' s_mpl_ 


Como puede ver, en nuestro primer ejemplo usamos \+ para calificar el rango A-C (reemplazado a nivel mundial debido a la gramo calificador) como requerir uno o más ocurrencias. Tenga en cuenta que la sintaxis, específicamente, es \+. Sin embargo, cuando cambiamos esto \+ a +, El comando arrojó una salida completamente diferente. Esto es porque el + no se interpreta como un carácter más estándar, y no como un comando regex.

Esto fue probado posteriormente por el tercer comando en el que un literal +, así como el mi antes, fue capturado por la expresión regular [A-E]+, y transformado en _.

Mirando hacia atrás que el primer comando, ahora podemos ver cómo el \+ fue interpretado como una expresión regular no literal +, para ser procesado por sed.

Finalmente, en el último comando le decimos a SED que queremos específicamente usar la sintaxis extendida utilizando el -mi opción de sintaxis extendida a SED. Tenga en cuenta que el término extendido nos da una pista de lo que sucede en el fondo; La sintaxis de expresión regular es expandido para habilitar varios comandos regex, como en este caso +.

Una vez el -mi se usa, aunque todavía usamos + y no \+, SED interpreta correctamente el + Como una instrucción de expresión regular.

Cuando escribe muchas expresiones regulares, estas diferencias menores en la expresión de sus pensamientos a expresiones regulares se desvanecen en el fondo, y tenderá a recordar las más importantes.

Esto también resalta la necesidad de probar siempre expresiones regulares ampliamente, dada una variedad de posibles entradas, incluso las que no espera.

Ejemplo 2: modificación de cadena de servicio pesado

Para este ejemplo, y los posteriores, hemos preparado un archivo textual. Si desea practicar, puede usar los siguientes comandos para crear este archivo para usted:

$ ECHO 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFG 0123456789'> TEST1 $ CAT TEST1 ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFG 0123456789 

Veamos ahora nuestro primer ejemplo de modificaciones de cadenas: nos gustaría la segunda columna (Abcdefg) venir antes del primero (ABCDEFGHIJKLMNOPQRSTU VWXYZ).

Como comienzo, hacemos este intento ficticio:

$ CAT TEST1 ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFG 0123456789 $ CAT TEST1 | sed -e 's | ([a -o]+).*([A-Z]+) | \ 2 \ 1 | ' G ABCDEFGHIJKLMNO 0123456789 

¿Entiendes esta expresión regular?? Si es así, ya es un escritor de expresión regular muy avanzado, y puede optar por adelantarse a los siguientes ejemplos, rompiendo sobre ellos para ver si puede comprenderlos rápidamente o necesita un poco de ayuda.

Lo que estamos haciendo aquí es gato (mostrar) nuestro archivo test1 y analizarlo con una expresión regular extendida (gracias a la -mi opción) Usando SED. Podríamos haber escrito esta expresión regular utilizando una expresión regular no extendida (en SED) de la siguiente manera;

$ Cat Test1 | sed 's | \ ([a-o] \+\).*\ ([A-z] \+\) | \ 2 \ 1 | ' G ABCDEFGHIJKLMNO 0123456789 

Que es exactamente lo mismo, excepto que agregamos un \ personaje antes de cada (, ) y + carácter, que indica a SED, queremos que sean analizados como código de expresión regular, y no como caracteres normales. Echemos un vistazo a la expresión regular en sí misma.

Usemos el formato de expresión regular extendido para esto, ya que es más fácil analizar visualmente.

s | ([a-o]+).*([A-Z]+) | \ 2 \ 1 | 

Aquí estamos utilizando el comando SED Sustitutute (s al comienzo del comando), seguido de una búsqueda (primero |… | parte) y reemplazar (segundo |… | parte) sección.

En la sección de búsqueda, tenemos dos grupos de selección, cada uno rodeado y limitado por ( y ), a saber ([A-O]+) y ([A-Z]+). Estos grupos de selección, en el orden que reciben, se buscarán mientras buscan las cuerdas. Tenga en cuenta que entre el grupo de selección, tenemos un .* expresión regular, que básicamente significa cualquier personaje, 0 o más veces. Esto coincidirá con nuestro espacio entre ABCDEFGHIJKLMNOPQRSTU VWXYZ y Abcdefg en el archivo de entrada, y potencialmente más.

En nuestro primer grupo de búsqueda, buscamos al menos una aparición de A-O seguido de cualquier otro número de ocurrencias de A-O, indicado por el + Calificatorio. En el segundo grupo de búsqueda, buscamos letras mayúsculas entre A y Z, y esto nuevamente una o más veces en secuencia.

Finalmente, en nuestra sección de reemplazo del sed Comando de expresión regular, lo haremos volver a llamar/Recordar el texto seleccionado por estos grupos de búsqueda e inserte como cadenas de reemplazo. Tenga en cuenta que el orden se está revertiendo; Primera salida El texto coincidente por el segundo grupo de selección (mediante el uso de \ 2 indicando el segundo grupo de selección), luego el texto coincidía con el primer grupo de selección (\ 1).

Si bien esto puede sonar fácil, el resultado en cuestión (G ABCDEFGHIJKLMNO 0123456789) puede no estar claro de inmediato. ¿Cómo perdimos? A B C D E F Por ejemplo? También perdimos pqrstuvwxyz - Te diste cuenta?



Lo que pasó es esto; Nuestro primer grupo de selección capturó el texto abcdefghijklmno. Entonces, dado el .* (cualquier personaje, 0 o más veces) Todos los personajes fueron emparejados, y esto importante; En la medida máxima, hasta que encontremos la siguiente expresión regular correspondiente que corresponde, si alguna. Entonces, finalmente, combinamos cualquier carta del ARIZONA rango, y esta una vez más.

¿Estás empezando a ver por qué perdimos? A B C D E F y pqrstuvwxyz? Si bien de ninguna manera es evidente, el .* siguió a los personajes de emparejamiento hasta el último ARIZONA fue emparejado, lo que sería GRAMO en el Abcdefg cadena.

Aunque especificamos uno o mas (mediante el uso de +) Caracteres para que coincidan, esta expresión regular particular fue interpretada correctamente por SED de izquierda a derecha, y SED solo se detuvo con el emparejamiento de cualquier carácter (.*) cuando ya no podía cumplir con la premisa de que habría al menos uno mayúscula ARIZONA Próximo.

En total, pqrstuvwxyz abcdef fue reemplazado por .* En lugar de solo el espacio, ya que uno leería esta expresión regular en una lectura más natural, pero incorrecta,. Y, porque no estamos capturando lo que fue seleccionado por .*, Esta selección simplemente se dejó caer desde la salida.

Tenga en cuenta también que cualquier pieza que no coincida con la sección de búsqueda simplemente se copie a la salida: sed solo actuará sobre lo que la expresión regular (o coincidencia de texto) encuentre.

Ejemplo 3: Seleccionar todo lo que no es

El ejemplo anterior también nos lleva a otro método interesante, que es probable que use un poco si escribe expresiones regulares regularmente, y eso es seleccionar texto por medio de coincidencias Todo lo que no es. Suena como algo divertido de decir, pero no está claro lo que significa? Veamos un ejemplo:

$ CAT TEST1 ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFG 0123456789 $ CAT TEST1 | sed -e 's | [^]*| _ |' _ ABCDEFG 0123456789 

Una simple expresiones regulares, pero muy poderosa. Aquí, en lugar de usar .* de alguna forma o de manera que hemos usado [^]*. En lugar de decir (por .*) coincidir con cualquier personaje, 0 o más veces, Ahora declaramos coincidir con cualquier personaje sin espacio, 0 o más veces.

Si bien esto se ve relativamente fácil, pronto se dará cuenta del poder de escribir expresiones regulares de esta manera. Piense por ejemplo, por ejemplo, sobre nuestro último ejemplo, en el que de repente tenemos una gran parte del texto que coincide de una manera algo inesperada. Esto podría evitarse cambiando ligeramente nuestra expresión regular del ejemplo anterior, como sigue:

$ Cat Test1 | sed -e 's | ([a-o]+) [^a]+([a-z]+) | \ 2 \ 1 |' ABCDEFG ABCDEFGHIJKLMNO 0123456789 

Aún no es perfecto, pero mejor ya; Al menos pudimos preservar A B C D E F parte. Todo lo que hicimos fue cambiar .* a [^A]+. En otras palabras, sigue buscando personajes, al menos uno, excepto para A. Una vez A se encuentra que parte de la expresión regular se detiene. A en sí tampoco se incluirá en el partido.

Ejemplo 4: Volviendo a nuestro requisito original

¿Podemos hacerlo mejor y, de hecho??

Sí, pero no manteniendo la expresión regular como es. Después de todo, está haciendo lo que solicitamos que hiciera; coincidir con todos los personajes de A-O Usar el primer grupo de búsqueda (y salida más tarde al final de la cadena), y luego desechar Cualquier personaje hasta que llegue SED A. Podríamos hacer una resolución final del problema, recuerde que solo queríamos que el espacio coincida, extendiendo/cambiando el A-O a Arizona, o simplemente agregando otro grupo de búsqueda y coincidiendo con el espacio literalmente:

$ Cat Test1 | sed -e 's | ([a-o]+) ([^]+) [] ([a-z]+) | \ 3 \ 1 \ 2 |' ABCDEFG ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 

Excelente! Pero la expresión regular se ve demasiado compleja ahora. Coincidimos A-O Una o más veces en el primer grupo, luego cualquier carácter sin espacio (hasta que SED encuentre un espacio o el final de la cuerda) en el segundo grupo, luego un espacio literal y finalmente ARIZONA una o más veces.

¿Podemos simplificarlo?? Sí. Y esto debería resaltar cómo se pueden complicar fácilmente los scripts de expresión regulares.

$ Cat Test1 | sed -e 's | ([^]+) ([^]+) | \ 2 \ 1 |' ABCDEFG ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 $ CAT TEST1 | AWK 'imprima $ 2 "" $ 1 "" $ 3' ABCDEFG ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 


Ambas soluciones logran el requisito original, utilizando diferentes herramientas, una regex muy simplificada para el comando SED y sin errores, al menos para las cadenas de entrada proporcionadas. ¿Puede esto salir mal fácilmente??

$ CAT TEST1 ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFG 0123456789 $ CAT TEST1 | sed -e 's | ([^]+) ([^]+) | \ 2 \ 1 |' ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 ABCDEFG 

Sí. Todo lo que hicimos fue agregar un espacio adicional en la entrada, y el uso de la misma expresión regular, nuestra salida ahora es completamente incorrecta; Se intercambiaron la segunda y tercera columnas en lugar del puño dos. Nuevamente, se resalta la necesidad de probar expresiones regulares en profundidad y con entradas variadas. La diferencia en la salida es simplemente porque el patrón sin espacio sin espacio solo podría coincidir con la última parte de la cadena de entrada debido al espacio doble.

Ejemplo 5: LS Gotcha?

A veces, una configuración de nivel de sistema operativo, como por ejemplo, usando la salida de color para listados de directorio o no (que puede establecerse de forma predeterminada!), hará que los scripts de línea de comandos se comporten de manera errática. Si bien no es una falla directa de las expresiones regulares de ninguna manera, es una gotcha con la que se puede encontrar más fácilmente al usar expresiones regulares. Veamos un ejemplo:

LS Color La producción contamina el resultado de un comando que contiene expresiones regulares
$ ls -d t* test1 test2 $ ls -d t* 2 | sed 's | 2 | 1 |' test1 $ ls -d t*2 | sed 's | 2 | 1 |' | xargs ls ls: no se puede acceder "

En este ejemplo, tenemos un directorio (test2) y un archivo (test1), ambos enumerados por el original LS -D dominio. Luego buscamos todos los archivos con un patrón de nombre de archivo de t*2, y retire el 2 del nombre de archivo usando sed. El resultado es el texto prueba. Parece que podemos usar esta salida prueba inmediatamente para otro comando, y lo enviamos a través de Xargs hacia LS comando, esperando el LS comandar para enumerar el archivo prueba1.

Sin embargo, esto no sucede, y en cambio obtenemos una salida muy compleja a humanidad. La razón es simple: el directorio original se enumeró en un color azul oscuro, y este color se define como una serie de códigos de color. Cuando ves esto por primera vez, la salida es difícil de entender. Sin embargo, la solución es simple;

$ ls -d -color = nunca t*2 | sed 's | 2 | 1 |' | XARGS LS TEST1 

Hicimos el LS Salida del comando El listado sin usar ningún color. Esto soluciona completamente el problema en cuestión y nos muestra cómo podemos mantener en el fondo de nuestras mentes la necesidad de evitar configuraciones y gotchas específicos de SO pequeños, pero significativos, lo que puede romper nuestro trabajo de expresión regular cuando se ejecuta en diferentes entornos, en hardware diferente, o en diferentes sistemas operativos.

Listo para explorar más por su cuenta? Veamos algunas de las expresiones regulares más comunes disponibles en Bash:

Expresión Descripción
. Cualquier personaje, excepto Newline
[C.A] Un carácter de la gama seleccionada, en este caso A, B, C
[ARIZONA] Un carácter de la gama seleccionada, en este caso A-Z
[0-9AF-Z] Un carácter de la gama seleccionada, en este caso 0-9, A y F-Z
[^A-Za-Z] Un personaje fuera de la gama seleccionada, en este caso, por ejemplo, '1' calificaría
\* o * Cualquier número de partidos (0 o más). Use * cuando use expresiones regulares donde las expresiones extendidas no están habilitadas (ver el primer ejemplo anterior)
\+ o + 1 o más partidos. Comentario idem como *
\ (\) Grupo de captura. La primera vez que se usa, el número de grupo es 1, etc.
^ Inicio de la cadena
ps Final de la cuerda
\d Un dígito
\D Un no dígito
\s Un espacio en blanco
\S Un espacio no blanco
A | D Un personaje de los dos (una alternativa al uso []), 'A' o 'D'
\ Escapa de los caracteres especiales, o indica que queremos usar una expresión regular donde las expresiones extendidas no están habilitadas (ver el primer ejemplo anterior)
\b Personaje de Backspace
\norte Carácter nuevo
\ r Carácter de retorno del carro
\ t Pestañas carácter

Conclusión

En este tutorial, parecimos en profundidad en las expresiones regulares de Bash. Descubrimos la necesidad de probar nuestras expresiones regulares en detalle, con entradas variadas. También vimos cómo las pequeñas diferencias del sistema operativo, como usar color para LS Los comandos o no pueden conducir a resultados muy inesperados. Aprendimos la necesidad de evitar patrones de búsqueda de expresión regular demasiado genéricos y cómo usar expresiones regulares extendidas.

Disfrute de escribir expresiones regulares avanzadas y déjenos un comentario a continuación con sus mejores ejemplos!

Tutoriales de Linux relacionados:

  • Bash regexps para principiantes con ejemplos
  • Expresiones regulares de Python con ejemplos
  • Manipulación de Big Data para diversión y ganancias Parte 3
  • Una introducción a la automatización, herramientas y técnicas de Linux
  • Cosas para instalar en Ubuntu 20.04
  • Manipulación de Big Data para diversión y ganancias Parte 2
  • Manipulación de Big Data para la diversión y las ganancias Parte 1
  • Mastering Bash Script Loops
  • Mint 20: Mejor que Ubuntu y Microsoft Windows?
  • Cosas que hacer después de instalar Ubuntu 20.04 fossa focal Linux