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... (Enlace
a documento adjunto aclaratorio
sobre retroreferencias en regexp)
Para REs básicas, las subexpresiones
deben estar delimitadas por \(
y \)
, con (
y )
por sí mismos se
interpretan como 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 (Enlace útil para
consultas)
-
¿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.