103.7 Lección 1
Certificación: |
LPIC-1 |
---|---|
Versión: |
5.0 |
Tema: |
103 Comandos GNU y Unix |
Objetivo: |
103.7 Buscar archivos de texto usando expresiones regulares |
Lección: |
1 de 2 |
Introducción
Los algoritmos de búsqueda de cadenas son ampliamente utilizados por varias tareas de procesamiento de datos, tanto que los sistemas operativos similares a Unix tienen su propia implementación ubicua: Expresiones regulares (Regular expressions), a menudo abreviadas como REs. Las expresiones regulares consisten en secuencias de caracteres que forman un patrón genérico que se utiliza para localizar y, a veces, modificar una secuencia correspondiente en una cadena de caracteres más grande. Las expresiones regulares amplían enormemente la capacidad de:
-
Escribir reglas de análisis para solicitudes en servidores HTTP, nginx en particular.
-
Escribir scripts que conviertan conjuntos de datos basados en texto a otro formato.
-
Buscar ocurrencias de interés en entradas de diario o documentos.
-
Filtrar documentos de marcado, manteniendo el contenido semántico.
La expresión regular más simple contiene al menos un átomo. Un átomo, llamado así porque es el elemento básico de una expresión regular, es sólo un carácter que puede tener o no un significado especial. La mayoría de los caracteres ordinarios son inequívocos, conservan su significado literal, mientras que otros tienen un significado especial:
.
(punto)-
Átomo coincide con cualquier carácter.
^
(signo de intercalación)-
Átomo coincide con el comienzo de una línea.
$
(signo de dólar)-
Átomo coincide con el final de una línea.
Por ejemplo, la expresión regular bc
, compuesta por los átomos literales b
y c
, se puede encontrar en la cadena abcd
, pero no en la cadena a1cd
. Por otro lado, la expresión regular .c
puede encontrarse en ambas cadenas de caracteres abcd
y a1cd
, ya que el punto .
coincide con cualquier carácter.
Los átomos de signo de intercalación y dólar se utilizan cuando sólo son de interés las coincidencias al principio o al final de la cadena. Por eso también se les llama anchors (anclas). Por ejemplo, cd
se puede encontrar en abcd
, pero ^cd
no. De manera similar, ab
se puede encontrar en abcd
, pero ab$
no. El signo de intercalación ^
es un carácter literal excepto cuando está al principio y $
es un carácter literal excepto cuando está al final de la expresión regular.
Expresión de corchetes
Hay otro tipo de átomo llamado bracket expression (expresión de corchetes). Aunque no es un solo carácter, los corchetes []
(incluido su contenido) se consideran un solo átomo. Una expresión entre corchetes suele ser sólo una lista de caracteres literales encerrados por []
, haciendo que el átomo coincida con cualquier carácter de la lista. Por ejemplo, la expresión [1b]
se puede encontrar en ambas cadenas, abcd
y a1cd
. Para especificar los caracteres a los que no debe corresponder el átomo, la lista debe comenzar con ^
, como en [^1b]
. También es posible especificar rangos de caracteres en expresiones entre corchetes. Por ejemplo, [0−9]
coincide con los dígitos del 0 al 9 y [a−z]
coincide con cualquier letra minúscula. Los rangos deben usarse con precaución, ya que pueden no ser consistentes en distintas configuraciones regionales.
Las listas de expresiones entre corchetes también aceptan clases en lugar de sólo caracteres y rangos individuales. Las clases de caracteres tradicionales son:
[:alnum:]
-
Representa un carácter alfanumérico.
[:alpha:]
-
Representa un carácter alfabético.
[:ascii:]
-
Representa un carácter que encaja en el juego de caracteres ASCII.
[:blank:]
-
Representa un carácter en blanco, es decir, un espacio o una tabulación.
[:cntrl:]
-
Representa un carácter de control.
[:digit:]
-
Representa un dígito (0 a 9).
[:graph:]
-
Representa cualquier carácter imprimible excepto el espacio.
[:lower:]
-
Representa un carácter en minúscula.
[:print:]
-
Representa cualquier carácter imprimible, incluido el espacio.
[:punct:]
-
Representa cualquier carácter imprimible que no sea un espacio ni un carácter alfanumérico.
[:space:]
-
Representa caracteres de espacio en blanco: espacio, avance de formulario (
\f
), nueva línea (\n
), retorno de carro (\r
), tabulación horizontal (\t
) y tabulación vertical (\v
). [:upper:]
-
Representa una letra mayúscula.
[:xdigit:]
-
Representa dígitos hexadecimales (de 0 a F).
Las clases de caracteres se pueden combinar con caracteres y rangos individuales, pero no se pueden usar como punto final de un rango. Además, las clases de caracteres pueden usarse sólo en expresiones de corchetes, no como un átomo independiente fuera de los corchetes.
Cuantificadores
El alcance de un átomo, ya sea un átomo de un solo carácter o un átomo de corchete, se puede ajustar utilizando un cuantificador de átomos. Los cuantificadores de átomos definen secuencias de átomos, es decir, las coincidencias ocurren cuando se encuentra una repetición contigua para el átomo en la cadena. La subcadena correspondiente a la coincidencia se llama pieza. No obstante, los cuantificadores y otras características de las expresiones regulares se tratan de manera diferente según el estándar que se utilice.
Según lo define POSIX, hay dos tipos de expresiones regulares: expresiones regulares “básicas” y expresiones regulares “extendidas”. La mayoría de los programas relacionados con texto en cualquier distribución convencional de Linux admiten ambas formas, por lo que es importante conocer sus diferencias para evitar problemas de compatibilidad y elegir la implementación más adecuada para la tarea prevista.
El cuantificador *
tiene la misma función tanto en los RE básicos como en los extendidos (el átomo aparece cero o más veces) y es un carácter literal si aparece al principio de la expresión regular o si está precedido por una barra invertida \
. El cuantificador de signo más ` seleccionará piezas que contengan una o más coincidencias de átomos en secuencia. Con el cuantificador de signo de interrogación `?`, Se producirá una coincidencia si el átomo correspondiente aparece una vez o si no aparece en absoluto. Si está precedido por una barra invertida `\`, se obvia su significado especial. Las expresiones regulares básicas también admiten cuantificadores `
y ?
, Pero deben ir precedidas de una barra invertida. A diferencia de las expresiones regulares extendidas, +
y ?
Por sí mismos son caracteres literales en expresiones regulares básicas.
Límites
Un bound (límite) es un cuantificador de átomos que, como su nombre indica, permite al usuario especificar límites cuantitativos precisos para un átomo. En las expresiones regulares extendidas, un límite puede aparecer de tres formas:
{i}
-
El átomo debe aparecer exactamente
i
veces (i
un número entero). Por ejemplo,[[:blank:]]{2}
coincide con exactamente dos caracteres en blanco. {i,}
-
El átomo debe aparecer al menos
i
veces (i
un número entero). Por ejemplo,[[:blank:]]{2,}
coincide con cualquier secuencia de dos o más caracteres en blanco. {i,j}
-
El átomo debe aparecer al menos
i
veces y como máximoj
veces (i
yj
números enteros,j
mayor quei
). Por ejemplo,xyz{2,4}
coincide con la cadenaxy
seguida de entre dos y cuatro caracteresz
.
En cualquier caso, si una subcadena coincide con una expresión regular y una subcadena más larga que comienza en el mismo punto también coincide, se considerará la subcadena más larga.
Las expresiones regulares básicas también admiten límites, pero los delimitadores deben estar precedidos por \
: \{
y \}
. Por sí mismos, {
y }
se interpretan como caracteres literales. Un \{
seguido de un carácter que no sea un dígito es un carácter literal, no el comienzo de un límite.
Ramas y referencias posteriores
Las expresiones regulares básicas también difieren de las expresiones regulares extendidas en otro aspecto importante: una expresión regular extendida se puede dividir en ramas, cada una de las cuales es una expresión regular independiente. Las ramas están separadas por |
y la expresión regular combinada coincidirá con cualquier cosa que corresponda a cualquiera de las ramas. Por ejemplo, he|him
coincidirá si la subcadena he
o him
se encuentran en la cadena que se está examinando. Las expresiones regulares básicas interpretan |
como un carácter literal. Sin embargo, la mayoría de los programas que soportan expresiones regulares básicas permitirán ramificaciones con \|
.
Una expresión regular extendida encerrada entre ()
se puede usar en una referencia posterior. Por ejemplo, ([[:dígito:]])\1
coincidirá con cualquier expresión regular que se repita al menos una vez, porque el \1
en la expresión es la referencia posterior a la pieza que coincide con la primera subexpresión entre paréntesis. Si existe más de una subexpresión entre paréntesis en la expresión regular, se puede hacer referencia a ellas con \2
,\3
, etc.
Para REs básicas, las subexpresiones deben estar delimitadas por \(
y \)
, con (
y )
por sí mismos caracteres ordinarios. El índice de referencia inversa se usa del mismo modo que en las expresiones regulares extendidas.
Búsqueda con expresiones regulares
El beneficio inmediato que ofrecen las expresiones regulares es mejorar las búsquedas en sistemas de archivos y en documentos de texto. La opción -regex
del comando find
permite probar cada ruta en una jerarquía de directorios contra una expresión regular. Por ejemplo,
$ find $HOME -regex '.*/\..*' -size +100M
busca archivos de más de 100 megabytes (100 unidades de 1048576 bytes), pero sólo en rutas dentro del directorio de inicio del usuario que contienen una coincidencia con .*/\..*
, es decir, un /.
rodeado por cualquier otro número de caracteres. En otras palabras, sólo se enumerarán los archivos ocultos o los archivos dentro de los directorios ocultos, independientemente de la posición de /.
en la ruta correspondiente. Para expresiones regulares que no distinguen entre mayúsculas y minúsculas, se usará en su lugar la opción -iregex
:
$ find /usr/share/fonts -regextype posix-extended -iregex '.*(dejavu|liberation).*sans.*(italic|oblique).*' /usr/share/fonts/dejavu/DejaVuSansCondensed-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSansCondensed-Oblique.ttf /usr/share/fonts/dejavu/DejaVuSans-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSans-Oblique.ttf /usr/share/fonts/dejavu/DejaVuSansMono-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSansMono-Oblique.ttf /usr/share/fonts/liberation/LiberationSans-BoldItalic.ttf /usr/share/fonts/liberation/LiberationSans-Italic.ttf
En este ejemplo, la expresión regular contiene ramas (escritas en modo extendido) para listar sólo archivos de fuentes específicos bajo la jerarquía de directorios /usr/share/fonts
. Las expresiones regulares extendidas no son compatibles de forma predeterminada, pero find
permite habilitarlas con -regextype posix-extended
o -regextype egrep
. El estándar RE predeterminado para find
es findutils-default, que es prácticamente un clon básico de expresión regular.
A menudo es necesario pasar la salida de un programa al comando less
cuando no cabe en la pantalla. El comando less
divide su entrada en páginas, una pantalla completa a la vez, lo que permite al usuario navegar fácilmente por el texto hacia arriba y hacia abajo. Además, less
también permite al usuario realizar búsquedas basadas en expresiones regulares. Esta característica es notablemente importante porque less
es el paginador predeterminado que se usa para muchas tareas diarias, como inspeccionar entradas de diario o consultar páginas de manual. Al leer una página de manual, por ejemplo, al presionar la tecla / se abrirá un mensaje de búsqueda. Este es un escenario típico en el que las expresiones regulares son útiles, ya que las opciones de comando se enumeran justo después de un margen de página. Sin embargo, la misma opción puede aparecer muchas veces en el texto, lo que hace que las búsquedas literales sean inviables. Independientemente de eso, al escribir ^[[:blank:]]-o
— o de manera más simple:`^-o` — en el indicador de búsqueda y presionar Enter se saltará inmediatamente a la sección -o
(si existe), permitiendo consultar la descripción de una opción de manera más rápida.
Ejercicios Guiados
-
¿Qué expresión regular extendida coincidiría con cualquier dirección de correo electrónico, como
info@example.org
? -
¿Qué expresión regular extendida sólo coincidiría con cualquier dirección IPv4 en el formato estándar de cuatro puntos, como
192.168.15.1
? -
¿Cómo se puede usar el comando
grep
para listar el contenido del archivo/etc/services
, descartando todos los comentarios (líneas que comienzan con#
)? -
El archivo
domains.txt
contiene una lista de nombres de dominio, uno por línea. ¿Cómo se usaría el comandoegrep
para listar solo los dominios.org
o.com
?
Ejercicios Exploratorios
-
Desde el directorio actual, ¿cómo usaría el comando
find
con una expresión regular extendida para buscar todos los archivos que no contienen un sufijo de archivo estándar (los nombres de archivo que no terminan en.txt
o.c
, por ejemplo)? -
El comando
less
es el paginador predeterminado para mostrar archivos de texto largos en el entorno de shell. Al escribir/
, se puede ingresar una expresión regular en el campo de búsqueda para saltar a la primera coincidencia correspondiente. Para permanecer en la posición actual del documento y sólo resaltar las coincidencias correspondientes, ¿qué combinación de teclas se debe ingresar en el campo de búsqueda? -
Con
less
, ¿cómo sería posible filtrar la salida para que sólo se muestren las líneas que coinciden con una expresión regular?
Resumen
Esta lección cubre el soporte general de Linux para expresiones regulares, un estándar ampliamente utilizado cuyas capacidades de búsqueda de patrones son compatibles con la mayoría de los programas relacionados con texto. La lección pasa por los siguientes pasos:
-
¿Qué es una expresión regular?
-
Los componentes principales de una expresión regular.
-
Las diferencias entre expresiones regulares regulares y extendidas.
-
¿Cómo realizar búsquedas simples de texto y archivos usando expresiones regulares?
Respuestas a los ejercicios guiados
-
¿Qué expresión regular extendida coincidiría con cualquier dirección de correo electrónico, como
info@example.org
?egrep "\S+@\S+\.\S+"
-
¿Qué expresión regular extendida sólo coincidiría con cualquier dirección IPv4 en el formato estándar de cuatro puntos, como
192.168.15.1
?egrep "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
-
¿Cómo se puede usar el comando
grep
para listar el contenido del archivo/etc/services
, descartando todos los comentarios (líneas que comienzan con#
)?grep -v ^# /etc/services
-
El archivo
domains.txt
contiene una lista de nombres de dominio, uno por línea. ¿Cómo se usaría el comandoegrep
para listar solo los dominios.org
o.com
?egrep ".org$|.com$" domains.txt
Respuestas a ejercicios exploratorios
-
Desde el directorio actual, ¿cómo usaría el comando
find
con una expresión regular extendida para buscar todos los archivos que no contienen un sufijo de archivo estándar (los nombres de archivo que no terminan en.txt
o.c
, por ejemplo)?find . -type f -regextype egrep -not -regex '.*\.[[:alnum:]]{1,}$'
-
El comando
less
es el paginador predeterminado para mostrar archivos de texto largos en el entorno de shell. Al escribir/
, se puede ingresar una expresión regular en el campo de búsqueda para saltar a la primera coincidencia correspondiente. Para permanecer en la posición actual del documento y sólo resaltar las coincidencias correspondientes, ¿qué combinación de teclas se debe ingresar en el campo de búsqueda?Presionando Ctrl+K antes de ingresar la expresión de búsqueda.
-
Con
less
, ¿cómo sería posible filtrar la salida para que sólo se muestren las líneas que coinciden con una expresión regular?Presionando & e ingresando la expresión de búsqueda.