Fuente: http://blog.desdelinux.net/con-el-terminal-uso-de-expresiones-regulares/
¿Qué es una expresión regular?
Una expresión regular es una serie de caracteres especiales que permiten describir un texto que queremos buscar. Por ejemplo, si quisiéramos buscar la palabra “linux” bastaría poner esa palabra en el programa que estemos usando. La propia palabra es una expresión regular. Hasta aquí parece muy simple, pero, ¿y si queremos buscar todos los números que hay en un determinado fichero? ¿O todas las lineas que empiezan por una letra mayúscula? En esos casos ya no se puede poner una simple palabra. La solución es usar una expresión regular.Expresiones regulares vs patrones de ficheros.
Antes de empezar a entrar en materia sobre las expresiones regulares, quiero aclarar un malentendido común sobre las expresiones regulares. Una expresión regular no es lo que ponemos como parámetro en los comandos como rm, cp, etc para hacer referencia a varios fichero que hay en el disco duro. Eso sería un patrón de ficheros. Las expresiones regulares, aunque se parecen en que usan algunos caracteres comunes, son diferentes. Un patrón de fichero se lanza contra los ficheros que hay en el disco duro y devuelve los que encajan completamente con el patrón, mientras que una expresión regular se lanza contra un texto y devuelve las lineas que contienen el texto buscado. Por ejemplo, la expresión regular correspondiente al patrón*.*
seria algo así como ^.*\..*$
Tipos de expresiones regulares.
No todos los programas utilizan las mismas expresiones regulares. Ni mucho menos. Existen varios tipos de expresiones regulares más o menos estándar, pero hay programas que cambian ligeramente la sintaxis, que incluyen sus propias extensiones o incluso que utilizan unos caracteres completamente diferentes. Por eso, cuando queráis usar expresiones regulares con algún programa que no conozcáis bien, lo primero es mirar el manual o la documentación del programa para ver cómo son las expresiones regulares que reconoce.En primer lugar, existen dos tipos principales de expresiones regulares, que están recogidas en el estándar POSIX, que es el que usan las herramientas de Linux. Son las expresiones regulares básicas y las extendidas. Muchos de los comandos que trabajan con expresiones regulares, como grep o sed, permiten usar estos dos tipos. Más abajo hablare de ellos. También están las expresiones regulares estilo PERL, y luego hay programas como vim o emacs que usan variantes de estas. Según lo que queramos hacer puede ser más adecuado usar unas u otras.
Probando expresiones regulares.
La sintaxis de las expresiones regulares no es nada trivial. Cuando tengamos que escribir una expresión regular complicada estaremos delante de una ristra de caracteres especiales imposibles de entender a primera vista, así que para aprender a usarlas es imprescindible contar con una forma de hacer todas las pruebas que queramos y ver los resultados fácilmente. Por eso voy a poner ahora varios comandos con los que podremos hacer las pruebas y experimentar todo lo que necesitemos hasta que tengamos las expresiones regulares dominadas.El primero de ellos es el comando grep. Este es el comando que usaremos con más frecuencia para hacer búsquedas. La sintaxis es la siguiente:
grep [-E] 'REGEX' FICHERO
COMANDO | grep [-E] 'REGEX'
Un truco que nos puede ayudar a ver el funcionamiento de las expresiones regulares es activar el uso del color en el comando grep. De esa manera, aparecerá resaltada la parte del texto que empareja con la expresión regular que estamos usando. Para activar el color en el comando grep basta con asegurarse que la variable de entorno
GREP_OPTIONS
contenga en valor --color
, cosa que se puede hacer con este comando:GREP_OPTIONS=--color
Otra forma de usar expresiones regulares es mediante el comando sed. Este es más adecuado para reemplazar texto, pero también puede usarse para hacer búsquedas. La sintaxis para ello sería así:
sed -n[r] '/REGEX/p' FICHERO
COMANDO | sed -n[r] '/REGEX/p'
Otro comando que también quiero nombrar es awk. Este comando puede usarse para muchas cosas, ya que permite escribir scripts en su propio lenguaje de programación. Si lo que queremos es buscar una expresión regular en un fichero o en la salida de un comando, la forma de usarlo sería la siguiente:
awk '/REGEX/' FICHERO
COMANDO | awk '/REGEX/'
Para hacer nuestras pruebas también necesitaremos un texto que nos sirva como ejemplo para hacer búsquedas en él. Podemos utilizar el siguiente texto:
- Lista de páginas wiki: ArchLinux: https://wiki.archlinux.org/ Gentoo: https://wiki.gentoo.org/wiki/Main_Page CentOS: http://wiki.centos.org/ Debian: https://wiki.debian.org/ Ubuntu: https://wiki.ubuntu.com/ - Fechas de lanzamiento: Arch Linux: 11-03-2002 Gentoo: 31/03/2002 CentOs: 14-05-2004 03:32:38 Debian: 16/08/1993 Ubuntu: 20/10/2004 Desde Linux Rulez.Este es el texto que usaré para los ejemplos del resto del post, así que os recomiendo que lo copiéis en un fichero para tenerlo a mano desde la terminal. Podéis poner el nombre que queráis. Yo lo he llamando regex.
Entrando en materia.
Ahora ya tenemos todo lo necesario para empezar a probar las expresiones regulares. Vayamos poco a poco. Voy a poner varios ejemplos de búsquedas con expresiones regulares en los que iré explicando para qué sirve cada carácter. No son ejemplos muy buenos, pero como me va a quedar un post muy largo no quiero complicarlo más. Y eso que sólo voy a arañar la superficie de lo que se puede hacer con expresiones regulares.Lo más sencillo de todo es buscar una palabra concreta, por ejemplo, supongamos que queremos buscar todas las lineas que contengan la palabra “Linux”. Esto es lo más fácil, ya que sólo tenemos que escribir:
grep 'Linux' regex
ArchLinux: https://wiki.archlinux.org/ Arch Linux: 11-03-2002 Desde Linux Rulez.
Estas son las tres lineas que contienen la palabra “Linux” la cual, si hemos usado el truco del color, aparecerá resaltada. Fijaros que reconoce la palabra que estamos buscando aunque forme parte de una palabra más larga como en “ArchLinux”. Sin embargo, no resalta la palabra “linux” que aparece en la URL “https://wiki.archlinux.org/”. Eso es porque ahí aparece con la “l” minúscula y la hemos buscado en mayúscula. El comando grep tiene opciones para esto, pero no voy a hablar de ellas en un artículo que trata sobre expresiones regulares.
Con esta sencilla prueba podemos sacar la primera conclusión:
- Un carácter normal puesto en una expresión regular empareja consigo mismo.
Supongamos ahora que queremos buscar la palabra “CentO” seguida de cualquier carácter, pero sólo un único carácter. Para esto podemos usar el carácter “.”, que es un comodín que empareja con un carácter cualquiera, pero sólo uno:
grep 'CentO.' regex
CentOS: http://wiki.centos.org/ CentOs: 14-05-2004 03:32:38
Lo que significa que incluye la “S” de “CentOS” aunque en un caso es mayúscula y en otro minúscula. Si apareciera en ese lugar cualquier otro carácter también lo incluiría. Ya tenemos la segunda regla:
- El carácter “.” empareja con cualquier carácter.
grep '200[24]' regex
Arch Linux: 11-03-2002 Gentoo: 31/03/2002 CentOs: 14-05-2004 03:32:38 Ubuntu: 20/10/2004Lo que nos lleva a la tercera regla:
- Varios caracteres encerrados entre corchetes emparejan con cualquiera de los caracteres que hay dentro de los corchetes.
grep ':[^/]' regex
ArchLinux: https://wiki.archlinux.org/ Gentoo: https://wiki.gentoo.org/wiki/Main_Page CentOS: http://wiki.centos.org/ Debian: https://wiki.debian.org/ Ubuntu: https://wiki.ubuntu.com/ Arch Linux: 11-03-2002 Gentoo: 31/03/2002 CentOs: 14-05-2004 03:32:38 Debian: 16/08/1993
Ubuntu: 20/10/2004
Ahora aparecen resaltados los “:” que hay detrás de los nombres de las distros, pero no los que hay en las URL porque los de las URL llevan “/” a continuación.
- Poner el carácter “^” al principio de un corchete empareja con cualquier carácter excepto con los demás caracteres del corchete.
grep '[0-9]-' regex
Arch Linux: 11-03-2002 CentOs: 14-05-2004 03:32:38
Se pueden especificar varios rangos dentro de los corchetes a incluso mezclar rangos con caracteres sueltos.
- Colocar dos caracteres separados por “-” dentro de los corchetes empareja con cualquier carácter dentro del rango.
grep -E 'https?' regex
ArchLinux: https://wiki.archlinux.org/ Gentoo: https://wiki.gentoo.org/wiki/Main_Page CentOS: http://wiki.centos.org/ Debian: https://wiki.debian.org/ Ubuntu: https://wiki.ubuntu.com/O sea que ya tenemos una nueva regla:
- Un carácter seguido de “?” empareja con ese carácter o con ninguno. Esto sólo es válido para expresiones regulares extendidas.
grep -E 'Debian|Ubuntu' regex
Debian: https://wiki.debian.org/ Ubuntu: https://wiki.ubuntu.com/ Debian: 16/08/1993 Ubuntu: 20/10/2004
- El carácter “|” sirve para separar varias expresiones regulares y empareja con cualquiera de ellas. También es específico de las expresiones regulares extendidas.
Para buscar una palabra que comienze por un caracter determinado colocamos el caracter ^ delante. Ejemplo:
$ grep '^#' /etc/default/grub
-v realiza la accion inversa:
$ grep -v '^#' /etc/default/grub
grep '\<Linux'
Arch Linux: 11-03-2002 Desde Linux Rulez.
También se puede usar “\>” para buscar palabras que no estén pegadas a otras por la derecha. Vamos con un ejemplo. Probemos este comando:
grep 'http\>' regex
El resultado que produce es este:
CentOS: http://wiki.centos.org/
Ha salido “http”, pero no “https”, porque en “https” todavía hay un carácter a la derecha de la “p” que puede formar parte de una palabra.
- Los caracteres “<” y “>” emparejan con el principio y el final de una palabra, respectivamente. Hay que escapar estos caracteres para que no se interpreten como caracteres literales.
grep -E ':[0-9]+' regex
Resultado:
CentOs: 14-05-2004 03:32:38
Queda resaltado también el número 38 porque también empieza con “:”.
- El carácter “+” empareja con el carácter que aparece a su izquierda repetido al menos una vez.
Primero vamos a buscar todas las secuencias de cuatro dígitos que haya:
grep '[0-9]\{4\}' regex
Fijaros en que hay que escapar las llaves si estamos usando expresiones regulares básicas, pero no si usamos las extendidas. Con extendidas sería así:
grep -E '[0-9]{4}' regex
Y el resultado en los dos casos sería este:
Arch Linux: 11-03-2002 Gentoo: 31/03/2002 CentOs: 14-05-2004 03:32:38 Debian: 16/08/1993 Ubuntu: 20/10/2004
- Los caracteres “{” y “}” con un número entre ellos emparejan con el carácter anterior repetido el número de veces indicado.
grep '[a-z]\{3,6\}' regex
- Lista de páginas wiki: ArchLinux: https://wiki.archlinux.org/ Gentoo: https://wiki.gentoo.org/wiki/Main_Page CentOS: http://wiki.centos.org/ Debian: https://wiki.debian.org/ Ubuntu: https://wiki.ubuntu.com/ - Fechas de lanzamiento: Arch Linux: 11-03-2002 Gentoo: 31/03/2002 CentOs: 14-05-2004 03:32:38 Debian: 16/08/1993 Ubuntu: 20/10/2004 Desde Linux Rulez.
Que, como veis, no se parece mucho a lo que queríamos. Eso es porque la expresión regular encuentra las letras dentro de otras palabras que son más largas. Probemos con esta otra versión:
grep '\<[a-z]\{3,6\}\>' regex
Resultado:
- Lista de páginas wiki: ArchLinux: https://wiki.archlinux.org/ Gentoo: https://wiki.gentoo.org/wiki/Main_Page CentOS: http://wiki.centos.org/ Debian: https://wiki.debian.org/ Ubuntu: https://wiki.ubuntu.com/
Esto ya se parece más a lo queríamos. Lo que hemos hecho es exigir que la palabra empiece justo delante de la primera letra y termine justo detrás de la última.
- Los caracteres “{” y “}” con dos números entre ellos separados por una coma emparejan con el carácter anterior repetido el número de veces indicado por los dos números.
grep 'wiki.*org' regex
ArchLinux: https://wiki.archlinux.org/ Gentoo: https://wiki.gentoo.org/wiki/Main_Page CentOS: http://wiki.centos.org/ Debian: https://wiki.debian.org/
Perfecto.
Ahora el último carácter que vamos a ver. El carácter “\” sirve para escapar el carácter de su derecha de manera que pierda el significado especial que tiene. Por ejemplo: Supongamos que queremos localizar la lineas que terminen en punto. Lo primero que se nos podría ocurrir podría ser esto:
grep '.$' regex
El resultado no es el que buscamos:
- Lista de páginas wiki: ArchLinux: https://wiki.archlinux.org/ Gentoo: https://wiki.gentoo.org/wiki/Main_Page CentOS: http://wiki.centos.org/ Debian: https://wiki.debian.org/ Ubuntu: https://wiki.ubuntu.com/ - Fechas de lanzamiento: Arch Linux: 11-03-2002 Gentoo: 31/03/2002 CentOs: 14-05-2004 03:32:38 Debian: 16/08/1993 Ubuntu: 20/10/2004 Desde Linux Rulez.
Esto es porque el carácter “.” empareja con cualquier cosa, así que esa expresión regular empareja con el último carácter de cada linea sea cual sea. La solución es esta:
grep '\.$' regex
Ahora el resultado sí que es el que queremos:
Desde Linux Rulez.
Expresiones regulares básicas de un solo carácter
Expresión regular | Se empareja con.... |
. | Cualquier carácter |
[ ] | Cualquiera de los caracteres que estén dentro de los corchetes |
[^ ] | Cualquiera de los caracteres que NO estén dentro de los corchetes |
^ | El principio de línea |
$ | El final de la línea |
* | Cero o mas ocurrencias de la expresión anterior (izquierda) |
\( \) | Permite agrupar varias expresiones regulares |
\ | Escapa un metacarácter |
Estas expresiones tienen las siguientes reglas especiales:
- Dentro de los corchetes [ ] los metacaracteres pierden su función especial y se tratan como literales.
- Hay varias excepciones a la regla anterior. Por ejemplo el carácter del “sombrerito” si se pone al inicio del corchete gana una funcionalidad diferente, como hemos visto en la tabla anterior.
Expresiones regulares básicas de repetición
Podemos repetir una expresión regular tantas veces como queramos con la secuencia \{ \}. Esta repetición se puede realizar de las siguientes formas:
Constructor | Resultado |
\{n\} | Concuerda exactamente con n ocurrencias de la expresión anterior |
\{n,\} | Concuerda con la menos n ocurrencias de la expresión anterior |
\{n, m\} | Concuerda con entre n y m ocurrencias de la expresión anterior |
Vamos a poner un ejemplo de este tipo de expresiones. Por ejemplo para buscar números de tres cifras podemos utilizar [0-9]\{3\}. Esto significa que repetirá 3 veces la búsqueda de números del cero al nueve, podría igualarse a [0-9] [0-9] [0-9]
Expresiones regulares extendidas
Como
hemos visto antes, para poder utilizar estas expresiones es necesario
darle al comando que se ejecuta el soporte para poder usarlas. Antes de
comenzar a verlas, es necesario ver reglas de conversión:
- El uso de las barras invertidas en los corchetes y los paréntesis no sirve en las expresiones regulares extendidas. Esto quiere decir que lo que hemos visto antes de \( \) y \{ \} ahora se debe poner de este modo: ( ) y { }. Si queremos que sean caracteres literales es necesario escaparlos.
Expresiones regulares extendidas de un solo carácter
En este grupo se agregaria estas expresiones:
Expresión regular | Concuerda con... |
+ | Una o mas ocurrencias de la expresión anterior (izquierda) |
? | Cero o una ocurrencia de la expresión anterior (izquierda) |
Otros metacaracteres utilizados en las expresiones regulares extendidas
Existen
otros metacaracteres para las expresiones regulares extendidas, entre
los cuales solamente vamos a ver uno muy utilizado que hace referencia a
la delimitación entre el principio y el fin de una palabra. Para
referenciar el principio se debe usar \< y para referenciar el final \>
Comentarios
Publicar un comentario