← Terminal y Línea de Comandos en Linux Bloque 6 · Filtrar y transformar texto · Tema 28 de 43

Tema 28

Expresiones regulares

Buscar la palabra «Rosario» es fácil. Buscar «cualquier fecha», «un importe de tres cifras o más» o «la línea donde el segundo campo es Luis» es otra cosa: ya no se busca un texto, sino una forma. Las expresiones regulares son un lenguaje pequeño para describir formas de texto. Tienen fama de ilegibles, y la merecen cuando se las escribe sin método. Aprendidas pieza por pieza son apenas una docena de símbolos, y sirven en grep, sed, awk, less, vim y prácticamente todos los lenguajes de programación.

1. Describir formas

Una expresión regular es un patrón que describe un conjunto de textos. Un texto coincide con la expresión si tiene la forma descrita.

El nombre se abrevia de muchas maneras: regex, regexp, «expresión». La idea se entiende con un ejemplo. Estas tres líneas son textos distintos, y tienen la misma forma: cuatro dígitos, un guion, dos dígitos, un guion, dos dígitos.

tres textos, una forma
2026-10-01
1999-12-31
2031-07-15

Una expresión regular permite decir exactamente eso, y con ella un programa puede encontrar todas las fechas de un archivo sin conocer ninguna de antemano:

Anatomía de una expresión regular que describe el comienzo de una fecha: el acento circunflejo indica el comienzo de la línea; los corchetes con cero guion nueve, un dígito; las llaves con un cuatro, cuatro veces; el guion, un guion literal; otra vez un dígito; y las llaves con un dos, dos veces ^ comienzo de línea [0-9] un dígito {4} cuatro veces - un guion [0-9] un dígito {2} dos veces
La expresión ^[0-9]{4}-[0-9]{2}, pieza por pieza. Una expresión regular se lee de izquierda a derecha, como una lista de condiciones.

Para practicar usaremos grep con dos opciones, y conviene fijarlas desde ahora:

OpciónPara qué la usamos
-EActiva la sintaxis extendida, la más cómoda. La diferencia con la básica está en la sección 9.
-oMuestra solo lo que coincidió. Es la mejor manera de ver qué describe una expresión.

Las expresiones se escriben siempre entre comillas simples. Usan casi todos los caracteres que la shell interpreta —asteriscos, signos de dólar, corchetes, barras— y hay que impedir que los toque, como aprendimos en el tema 9.

2. Las piezas del lenguaje

Dentro de una expresión hay dos clases de caracteres. La mayoría son literales: una a coincide con una «a», un 7 con un «7». Unos pocos son metacaracteres: no valen por sí mismos, sino que significan algo. Toda la sintaxis son estos, agrupados en cuatro familias:

FamiliaResponde aSímbolos
Clases¿Qué carácter?. [ ] [^ ]
Anclas¿En qué lugar?^ $ \b
Cuantificadores¿Cuántas veces?* + ? { }
Estructura¿Qué va junto, y qué alternativas hay?( ) |

A estos se suma la barra invertida, \, que quita o da significado al carácter siguiente. Las secciones que siguen recorren las familias en ese orden.

Una regla general, que ya vimos con grep: por defecto una expresión puede coincidir en cualquier parte de la línea. No hace falta que describa la línea entera; alcanza con que alguna porción de la línea tenga esa forma.

3. El punto: un carácter cualquiera

El punto coincide con exactamente un carácter, el que sea: una letra, un dígito, un espacio, un signo.

terminal, en ~/practica
$ cd ~/practica
$ grep 'l.z' tareas.txt              # una l, un carácter cualquiera, una z
Pagar la luz
$ grep -o 'm..' ventas.csv | sort -u  # una m y los dos caracteres siguientes
mon
mou

Cada punto ocupa una posición: m.. tiene tres caracteres de largo, ni más ni menos. Coincidió con el comienzo de «monitor» y de «mouse».

El punto es el metacarácter que más errores produce, por una razón simple: se lo escribe sin querer. Al buscar notas.txt o 192.168.1.1, los puntos están actuando como «cualquier carácter», y la búsqueda acepta más de lo debido. Lo vimos en el tema anterior, y la solución está en la sección 10.

4. Clases: uno de estos caracteres

Los corchetes describen también un solo carácter, pero limitado a un conjunto. Son los mismos de los comodines de la shell, con una diferencia en la negación:

ExpresiónCoincide con un carácter que…
[abc]Sea una a, una b o una c.
[a-z]Sea una minúscula.
[A-Za-z]Sea una letra, sin ñ ni tildes.
[0-9]Sea un dígito.
[^0-9]No sea un dígito. El circunflejo, al comienzo de los corchetes, niega.
[^,]No sea una coma.
terminal
$ grep -c '[MS]a' ventas.csv         # «Ma» o «Sa»: Marta o Salta
5
$ grep -c '0[56],' ventas.csv        # un 0, un 5 o un 6, y una coma: los días 5 y 6
4

Para los conjuntos de uso frecuente existen las clases con nombre, que conocimos en el tema 9 y que tienen en cuenta el idioma: incluyen la ñ y las vocales acentuadas. Se escriben dentro de unos corchetes, de ahí la doble pareja:

ClaseContieneAbreviatura en muchas herramientas
[[:digit:]]Los dígitos.\d, pero no en grep -E
[[:alpha:]]Las letras.—
[[:alnum:]]Letras y dígitos.—
[[:upper:]], [[:lower:]]Mayúsculas; minúsculas.—
[[:space:]]Espacios, tabulaciones y saltos de línea.\s
[[:punct:]]Signos de puntuación.—
[[:alnum:]_]Los caracteres «de palabra»: letras, dígitos y guion bajo.\w

Dentro de los corchetes casi todos los metacaracteres pierden su significado: [.*] coincide con un punto o un asterisco literales. Los únicos que conservan un papel son el circunflejo inicial, que niega; el guion entre dos caracteres, que forma un rango; y el corchete de cierre.

La clase negada [^,], «cualquier cosa menos una coma», es la pieza más útil para trabajar con archivos de campos. Vuelve a aparecer en casi todas las secciones siguientes.

5. Anclas: dónde debe estar

Las anclas no coinciden con ningún carácter. Coinciden con una posición, y sirven para exigir que el resto de la expresión esté en un lugar determinado de la línea.

AnclaPosiciónEjemploCoincide con
^El comienzo de la línea.^#Las líneas que empiezan con #.
$El final de la línea.bash$Las líneas que terminan en «bash».
^…$La línea entera.^$Las líneas vacías.
\bEl borde de una palabra.\bla\b«la» como palabra, no dentro de «plantas».
terminal
$ grep '^P' tareas.txt               # empieza con P
Pagar la luz
$ grep 's$' tareas.txt               # termina en s
Llamar a Luis
Regar las plantas
$ grep -c '^2026-10-0[12]' ventas.csv   # la fecha, al comienzo, es del día 1 o 2
4
$ grep -c 'nologin$' /etc/passwd     # cuentas cuya shell es nologin
38

Las anclas son lo que da precisión. En el tema 27, grep 10 ventas.csv coincidía con todas las líneas por culpa de las fechas. Con un ancla se dice dónde se quiere el número: ,10$ sería «un 10 como último campo».

El circunflejo tiene dos significados, y no hay que confundirlos: fuera de los corchetes y al principio es el ancla de comienzo; dentro de los corchetes y al principio es la negación. En ^[^#] aparecen los dos: «una línea que empieza con un carácter que no es #».

Los bordes de palabra se pueden escribir también por separado: \< para el comienzo de una palabra y \> para el final. La opción -w de grep equivale a rodear todo el patrón con \b.

6. Cuantificadores: cuántas veces

Hasta aquí cada pieza ocupaba una posición. Los cuantificadores permiten decir que una pieza se repite.

Un cuantificador indica cuántas veces puede aparecer el elemento que tiene inmediatamente antes. No significa nada por sí solo.

CuantificadorEl elemento anterior aparece…Se lee
*Cero o más veces.«Los que haya, incluso ninguno.»
+Una o más veces.«Al menos uno.»
?Cero o una vez.«Opcional.»
{3}Exactamente 3 veces.
{2,}2 veces o más.
{2,4}Entre 2 y 4 veces.

Se ven bien con un texto de prueba, pasado a grep con una cadena en línea, y la opción -o para mostrar cada coincidencia. El elemento cuantificado es la letra b:

terminal: la b puede aparecer…
$ grep -oE 'ab*c' <<< 'ac abc abbc abbbc' | paste -s -d' '      # cero o más veces
ac abc abbc abbbc
$ grep -oE 'ab+c' <<< 'ac abc abbc abbbc' | paste -s -d' '      # una o más
abc abbc abbbc
$ grep -oE 'ab?c' <<< 'ac abc abbc abbbc' | paste -s -d' '      # cero o una
ac abc
$ grep -oE 'ab{2,}c' <<< 'ac abc abbc abbbc' | paste -s -d' '   # dos o más
abbc abbbc

La potencia aparece al combinar un cuantificador con una clase. «Un dígito, una o más veces» es un número; «cualquier cosa menos una coma, cero o más veces» es un campo:

terminal
$ grep -oE '[0-9]+$' ventas.csv | paste -s -d' '     # el número que hay al final de cada línea
90 320 75 40 45 640 45 16 30 320
$ grep -E ',[0-9]{3}$' ventas.csv                    # importes de exactamente tres cifras
2026-10-01,Marta,Mendoza,monitor,1,320
2026-10-03,Ana,Mendoza,monitor,2,640
2026-10-06,Luis,Rosario,monitor,1,320
ExpresiónDescribe
[0-9]+Un número entero.
[a-z]+Una palabra en minúsculas.
[^,]*El contenido de un campo separado por comas.
.*Cualquier cosa, de cualquier largo: el «comodín» de las expresiones regulares.
[[:space:]]+Uno o más espacios en blanco.

La cuarta fila es la más usada, y la más mal usada. .* sirve para decir «y en el medio, lo que sea»: ^Luis.*monitor sería «empieza con Luis y más adelante dice monitor». Su problema es el de la sección siguiente.

7. La codicia

Cuando una expresión puede coincidir de varias maneras, hay una regla que decide:

Los cuantificadores son codiciosos: toman tanto texto como les sea posible, siempre que el resto de la expresión pueda seguir coincidiendo.

Con .*, que acepta cualquier carácter, eso significa llegar hasta lo más lejos que se pueda. Veamos el intento de extraer el primer campo de una línea como «todo, hasta una coma»:

terminal
$ head -n 1 ventas.csv | grep -oE '^.*,'      # «todo hasta una coma»… la última
2026-10-01,Luis,Rosario,teclado,2,
$ head -n 1 ventas.csv | grep -oE '^[^,]*,'   # «lo que no sea coma, y una coma»
2026-10-01,

La primera expresión no se detuvo en la primera coma. El punto acepta también las comas, de modo que .* avanzó hasta el final de la línea, y luego retrocedió lo mínimo necesario para que la coma final de la expresión encontrara con qué coincidir: la última del texto.

La segunda no tiene ese problema, porque [^,] no puede atravesar una coma: se detiene obligadamente en la primera.

En lugar de .*, decir qué no puede aparecer

Casi todos los resultados inesperados con expresiones regulares vienen de un .* que abarcó de más. La corrección es reemplazarlo por una clase negada que nombre el carácter en el que debe detenerse: [^,]* para un campo, [^"]* para el contenido de unas comillas, [^ ]* para una palabra. Es más preciso, y además más rápido.

8. Alternativa y grupos

La barra vertical separa alternativas: la expresión coincide si coincide cualquiera de ellas. Los paréntesis agrupan, con dos propósitos: limitar el alcance de una alternativa, y hacer que un cuantificador se aplique a varios caracteres en lugar de uno solo.

ExpresiónCoincide con
mouse|cable«mouse» o «cable».
^(Ana|Luis)«Ana» o «Luis», al comienzo de la línea.
^Ana|Luis«Ana» al comienzo, o «Luis» en cualquier parte. Sin paréntesis, la barra separa todo lo que tiene a cada lado.
(ja)+«ja», «jaja», «jajaja»… El + se aplica al grupo entero.
ja+«ja», «jaa», «jaaa»… El + se aplica solo a la a.
terminal
$ grep -cE 'mouse|cable' ventas.csv
5
$ grep -E ',(Ana|Marta),(Salta|Mendoza),' ventas.csv
2026-10-01,Marta,Mendoza,monitor,1,320
2026-10-02,Ana,Salta,mouse,5,75
2026-10-03,Ana,Mendoza,monitor,2,640
2026-10-06,Marta,Mendoza,mouse,2,30

La segunda búsqueda combina dos condiciones sobre dos campos, cosa que en el tema anterior exigía encadenar varios grep. Las comas incluidas en el patrón aseguran que cada nombre ocupe un campo entero.

Un grupo con cuantificador permite contar campos, y con eso llegar a una columna determinada. «Cuatro veces: un campo y su coma» deja la expresión parada al comienzo del quinto campo:

terminal: las ventas de exactamente diez unidades
$ grep -E '^([^,]*,){4}10,' ventas.csv
2026-10-02,Luis,Rosario,cable,10,40

Es la respuesta exacta a la pregunta que grep 10 no sabía responder. También es una expresión que ya cuesta leer; para seleccionar por columnas hay una herramienta mejor, awk, en el tema 30.

9. Básicas y extendidas

Hay un tropiezo histórico que conviene conocer antes de encontrarlo. Las herramientas de Unix entienden dos dialectos de expresiones regulares, que difieren en cómo se escriben algunos metacaracteres:

Básicas (BRE)Extendidas (ERE)
Las usangrep, sedgrep -E, sed -E, awk
Iguales en las dos. [ ] [^ ] ^ $ *
Una o más veces\++
Opcional\??
Repetición\{2,4\}{2,4}
Grupo\( \)( )
Alternativa\||

La regla es simétrica. En el dialecto básico, los signos + ? { } ( ) | son caracteres literales, y se vuelven especiales con una barra invertida delante. En el extendido es al revés: son especiales, y la barra invertida los vuelve literales.

terminal: la misma búsqueda, en los dos dialectos
$ grep -c ',[0-9]\{3\}$' ventas.csv   # básica
3
$ grep -cE ',[0-9]{3}$' ventas.csv    # extendida
3
$ grep -c 'mouse|cable' ventas.csv    # básica, sin escapar: busca el texto «mouse|cable»
0

La última línea es el síntoma típico: una expresión correcta que no encuentra nada, porque le falta la -E y sus símbolos se toman al pie de la letra.

Una costumbre: siempre -E

La sintaxis extendida es más legible y es la que usan awk y casi todos los lenguajes de programación. Conviene adoptarla como única: grep -E y sed -E, siempre. La básica hay que saber leerla, porque abunda en scripts y en documentación.

10. Escapar: el símbolo como texto

Cuando lo que se busca contiene un metacarácter, hay que quitarle su significado. Se hace anteponiéndole una barra invertida:

Para buscar…Se escribeSin escapar coincidiría con
Un punto\.Cualquier carácter.
notas.txtnotas\.txtTambién «notas-txt» o «notasXtxt».
Un signo de pesos\$El fin de línea.
Un asterisco\*Una repetición de lo anterior.
Un paréntesis, con -E\(El comienzo de un grupo.
Una barra invertida\\—
terminal
$ ls | grep -E '\.txt$'              # nombres que terminan en .txt
informe.txt
notas.txt
tareas.txt

Hay tres maneras de buscar un texto con símbolos, y conviene elegir según el caso:

RecursoEjemploCuándo
Barra invertidagrep '192\.168\.1\.1'Cuando el resto del patrón sí usa metacaracteres.
Corchetesgrep '192[.]168[.]1[.]1'Lo mismo; dentro de corchetes el punto es literal. A veces se lee mejor.
La opción -Fgrep -F '192.168.1.1'Cuando todo el patrón es texto literal.

La barra invertida es, entonces, el interruptor del lenguaje. Delante de un metacarácter, lo apaga. Delante de ciertas letras, enciende un significado: \b es un borde de palabra, \w un carácter de palabra, \s un espacio en blanco.

11. Retrorreferencias

Los paréntesis tienen un tercer efecto: el texto con el que coincide cada grupo queda recordado, y se lo puede volver a exigir más adelante en la misma expresión.

Una retrorreferencia, \1, \2…, coincide con el mismo texto que coincidió con el primer grupo entre paréntesis, con el segundo, y así.

No significa «otra vez la misma forma», sino «otra vez lo mismo». ([a-z])\1 no es «dos letras», sino «una letra, y enseguida esa misma letra»:

terminal: palabras con una letra doble
$ grep -oE '[a-z]*([a-z])\1[a-z]*' <<< 'carro perro casa llave mesa'
carro
perro
llave

Sirve para encontrar repeticiones: una palabra escrita dos veces seguidas por error, una línea cuyo primer campo y cuyo último campo son iguales. En las búsquedas se usa poco. Su lugar natural es el reemplazo, donde permite reordenar o conservar partes de lo encontrado: «pon el segundo grupo antes del primero». Es una de las herramientas centrales de sed, en el tema 29.

12. Construir una expresión paso a paso

Una expresión regular larga no se escribe de corrido. Se construye como una tubería: una pieza por vez, comprobando en cada paso con grep -oE qué está coincidiendo. El método tiene cuatro pasos.

  1. Mirar ejemplos reales de lo que se quiere encontrar, y de lo que no. observar
  2. Describir la forma en palabras, de izquierda a derecha. describir
  3. Traducir cada parte a su pieza, agregándolas de a una y probando. traducir
  4. Anclar y ajustar: ¿coincide con algo que no debía? ¿se pierde algo que debía encontrar? verificar

Lo aplicamos a una pregunta: ¿en qué líneas el vendedor, es decir, el segundo campo, es Ana? El primer intento es el ingenuo:

terminal: construyendo la expresión
$ grep -c 'Ana' ventas.csv                    # intento 1: «Ana», donde sea
3
$ grep -c ',Ana,' ventas.csv                  # intento 2: «Ana» como campo entero
3
$ grep -cE '^[^,]*,Ana,' ventas.csv           # intento 3: «Ana» como SEGUNDO campo
3

Los tres dan el mismo número, y sin embargo solo el tercero es correcto. El primero fallaría el día que hubiera una vendedora «Anabel», o una ciudad «Santa Ana». El segundo fallaría con un producto llamado «Ana». El tercero dice exactamente lo pedido: desde el comienzo de la línea, un campo, una coma, y «Ana» seguido de coma.

Que funcione con los datos de hoy no prueba que esté bien

Una expresión imprecisa da el resultado correcto mientras los datos no contengan el caso que la rompe. Por eso, además de mirar lo que encuentra, hay que pensar en lo que podría encontrar: probarla contra ejemplos inventados que no deberían coincidir es parte del trabajo.

La descripción en palabras, del segundo paso, es lo que vuelve legible cualquier expresión, propia o ajena. Esta, por ejemplo, selecciona de /etc/passwd las cuentas cuyo UID tiene cuatro cifras:

terminal
$ grep -E '^[^:]+:x:[0-9]{4}:' /etc/passwd
ana:x:1000:1000:Ana García,,,:/home/ana:/bin/bash
la misma expresión, leída
^           desde el comienzo de la línea
[^:]+       uno o más caracteres que no sean dos puntos: el nombre
:x:         el texto «:x:»
[0-9]{4}    exactamente cuatro dígitos: el UID
:           dos puntos, para que no haya un quinto dígito

13. No son comodines

En el tema 9 dejamos anotado que los comodines de la shell y las expresiones regulares comparten símbolos con significados distintos. Ahora se puede completar la tabla:

SímboloEn un comodín de la shellEn una expresión regular
*Cualquier cantidad de caracteres cualesquiera.Cero o más repeticiones del elemento anterior.
?Un carácter cualquiera.El elemento anterior es opcional.
.Un punto.Un carácter cualquiera.
[abc]Uno de esos caracteres.Lo mismo.
Negación en corchetes[!abc][^abc]
^ y $Caracteres comunes.Comienzo y fin de línea.
Quiero decirComodínExpresión regular
Cualquier cosa*.*
Un carácter cualquiera?.
Termina en .txt*.txt\.txt$
Empieza con fotofoto*^foto

Las dos últimas filas muestran una diferencia más de fondo. Un comodín debe describir el nombre entero; una expresión regular coincide con una parte, salvo que se la ancle. Por eso foto*, como expresión regular, significa otra cosa: «fot», seguido de cero o más letras o.

Y hay una diferencia de quién los interpreta, que decide cuál corresponde en cada lugar de una línea:

ComodinesExpresiones regulares
Los interpretaLa shell, antes de ejecutarEl programa que los recibe
Se comparan conNombres de archivosLíneas de texto
Se escribenSin comillasEntre comillas simples
Ejemplols *.csvgrep '\.csv$'

En grep -E '^Luis' *.csv conviven los dos: el patrón, entre comillas, es una expresión regular para grep; el último argumento, sin comillas, es un comodín para la shell.

14. Recetas y límites

Algunas expresiones de uso frecuente, para leer más que para copiar. Cada una se puede probar con grep -oE:

DescribeExpresión
Una línea vacía^$
Una línea vacía o solo con espacios^[[:space:]]*$
Una línea de comentario^[[:space:]]*#
Un número entero[0-9]+
Un número con decimales opcionales[0-9]+(\.[0-9]+)?
Una fecha año-mes-día[0-9]{4}-[0-9]{2}-[0-9]{2}
Una hora[0-9]{2}:[0-9]{2}(:[0-9]{2})?
Una dirección IP, de manera aproximada([0-9]{1,3}\.){3}[0-9]{1,3}
Una dirección de correo, de manera aproximada[[:alnum:]._-]+@[[:alnum:].-]+\.[a-z]{2,}
El primer campo de un CSV^[^,]*
El último campo de un CSV[^,]*$

Las palabras «de manera aproximada» no están de adorno. La expresión de la IP acepta 999.999.999.999, que no es una dirección válida. Describe la forma —cuatro grupos de dígitos separados por puntos—, no el significado. Esa es la frontera del lenguaje:

Las expresiones regulares…Consecuencia
Describen formas, no valores.No saben que 31 es un día válido y 32 no, ni comparan números.
No entienden estructuras anidadas.No sirven para analizar HTML, JSON ni código: para eso hay herramientas propias.
Crecen rápido en complejidad.Una expresión de dos renglones que nadie puede leer es un error futuro. Suele ser mejor dividir el trabajo en dos pasos simples.

Existe un tercer dialecto, más rico, que es el de la mayoría de los lenguajes de programación: las expresiones regulares de Perl, o PCRE. grep las acepta con la opción -P. Agregan atajos como \d para un dígito, y cuantificadores no codiciosos, como .*?, que toman lo mínimo. Lo aprendido en este tema vale también allí.

La referencia del tema, en sintaxis extendida:

SímboloSignifica
.Un carácter cualquiera.
[abc], [a-z]Un carácter del conjunto o del rango.
[^abc]Un carácter que no esté en el conjunto.
[[:digit:]], [[:alpha:]], [[:space:]]Un dígito; una letra; un espacio en blanco.
^, $Comienzo y fin de la línea.
\bBorde de palabra.
*, +, ?Lo anterior, cero o más veces; una o más; cero o una.
{n}, {n,}, {n,m}Lo anterior, n veces; n o más; entre n y m.
a|bUna alternativa u otra.
( )Agrupa, y recuerda lo que coincidió.
\1El texto del primer grupo.
\.Un punto literal; la barra invertida quita el significado especial.

Con grep las expresiones regulares sirven para encontrar. En el tema 29 las usamos para cambiar: sed busca con el mismo lenguaje, y reemplaza lo que encuentra.

15. Resumen

16. Preguntas de repaso

Intenta responder cada una antes de abrir la respuesta.

1. ¿Qué describe una expresión regular?

Una forma: un conjunto de textos que tienen cierta estructura, en lugar de un texto fijo.

2. ¿Con qué coincide c.sa?

Con una c, un carácter cualquiera, una s y una a: «casa», «cosa», «c3sa», «c sa».

3. ¿Qué diferencia hay entre [abc] y [^abc]?

La primera coincide con un carácter que sea a, b o c. La segunda, con un carácter que no sea ninguno de los tres.

4. ¿Qué significan ^ y $? ¿Y ^$?

El comienzo y el final de la línea. ^$ describe una línea vacía: un comienzo seguido inmediatamente de un final.

5. En ^[^#] el circunflejo aparece dos veces. ¿Qué significa cada uno?

El primero, fuera de los corchetes, es el ancla de comienzo de línea. El segundo, dentro, niega la clase. La expresión describe una línea que empieza con un carácter distinto de #.

6. ¿Qué diferencia hay entre *, + y ??

Los tres se aplican al elemento anterior: * lo admite cero o más veces, + una o más, y ? cero o una.

7. ¿Con qué coincide [0-9]{2,4}?

Con una secuencia de entre dos y cuatro dígitos.

8. ¿Qué significa que los cuantificadores sean codiciosos?

Que toman la mayor cantidad de texto posible que permita coincidir al resto de la expresión. .*, llega hasta la última coma de la línea, no hasta la primera.

9. ¿Por qué [^,]* es preferible a .* para describir un campo de un CSV?

Porque no puede atravesar una coma: se detiene al terminar el campo. .* acepta también las comas y abarca varios campos.

10. ¿Qué diferencia hay entre (ab)+ y ab+?

En la primera, el + se aplica al grupo: «ab», «abab», «ababab». En la segunda, solo a la b: «ab», «abb», «abbb».

11. grep 'error|aviso' archivo no encuentra nada, aunque las dos palabras están. ¿Por qué?

Porque sin -E, grep usa la sintaxis básica, donde la barra vertical es un carácter literal. Hay que escribir grep -E 'error|aviso'.

12. ¿Cómo se busca un punto literal?

Con \., con [.], o usando grep -F si todo el patrón es texto literal.

13. ¿Qué describe ^[^:]+:[^:]*:0: aplicado a /etc/passwd?

Las líneas cuyo tercer campo es 0: desde el comienzo, un primer campo no vacío, dos puntos, un segundo campo, dos puntos, y un cero seguido de dos puntos. Es la cuenta con UID 0, root.

14. ¿Qué hace \1?

Coincide con el mismo texto que coincidió con el primer grupo entre paréntesis. (.)\1 describe un carácter repetido dos veces seguidas.

15. ¿Qué significa *.txt como comodín, y cómo se escribe lo mismo como expresión regular?

Como comodín, un nombre que termina en .txt. Como expresión regular se escribe \.txt$: un punto literal, «txt», y el fin de la línea.

Para practicar

  1. Con grep -oE y la cadena 'gato gata gatos gatitos perro', prueba gat., gat[ao], gat[ao]s?, gat[a-z]+ y \bgat[ao]\b. Predice cada resultado antes de ejecutarlo.
  2. En ventas.csv, encuentra con una sola expresión cada cosa: las ventas del día 5; las de importe de dos cifras; las de teclado o monitor; las que no son de Rosario.
  3. Escribe una expresión que seleccione las líneas cuyo tercer campo es Salta, usando un grupo con cuantificador. Compruébala.
  4. Extrae con grep -oE todas las fechas distintas de ventas.csv, y todos los nombres de producto distintos.
  5. En /etc/passwd: cuenta las cuentas con UID de un solo dígito; lista las que tienen un directorio personal dentro de /home; encuentra las que no terminan en nologin ni en false.
  6. En informe.txt: cuenta las líneas vacías, las de comentario, y las que definen un servicio sobre un puerto de exactamente dos cifras ([[:space:]][0-9]{2}/).
  7. Compara grep -c 'a+' tareas.txt con grep -cE 'a+' tareas.txt y con grep -c 'a\+' tareas.txt. Explica los tres números.
  8. Prueba la codicia con grep -oE '".*"' <<< 'dijo "hola" y luego "chau"'. Corrige la expresión para obtener las dos citas por separado.
  9. Con ls -l /etc | grep -E, lista solo los directorios, luego solo los enlaces simbólicos, y luego los archivos que otros usuarios no pueden leer.
  10. Describe en palabras, pieza por pieza, la expresión del correo electrónico de la sección 14. Inventa una dirección que no debería ser válida y que, sin embargo, coincida.