Ya sabes cómo Bash procesa una línea antes de lanzarla: expande variables, sustituye comandos, parte por espacios. Esta lección añade la pieza más potente de ese procesamiento —el globbing— y a continuación algo que se le parece mucho y que no tiene nada que ver: las expresiones regulares.

Confundirlas es el error más extendido entre quienes llevan años usando la terminal. Se parecen porque ambas usan * y ?, y significan cosas distintas en cada una. La confusión no es académica: produce comandos que parecen funcionar, devuelven algo plausible y están mal. Al terminar esta lección tendrás la distinción grabada, sabrás describir cualquier conjunto de archivos con un patrón y construir expresiones regulares que resistan casos reales sobre acceso.log y reservas.csv.

Contenido

  1. Quién expande qué: el shell antes, el programa después
  2. Globbing: los comodines del shell
  3. Clases POSIX y expansión de llaves
  4. Opciones de globbing: globstar, dotglob, nullglob, failglob
  5. Expresiones regulares: BRE, ERE y PCRE
  6. Los metacaracteres, uno a uno
  7. Agrupación, alternancia y retrorreferencias
  8. Codicia: cuando la regex se lleva de más
  9. Método para construir una regex por pasos
  10. Regex prácticas del hilo conductor

  1. Quién expande qué: el shell antes, el programa después

La regla, en una frase: el globbing lo hace Bash sobre nombres de archivo antes de ejecutar el comando; las expresiones regulares las interpreta el programa sobre el texto que recibe.

El comando nunca llega a ver el comodín. Compruébalo con un comando que no hace nada más que imprimir sus argumentos:

operador@srv-tramontana:~$ cd /var/log/tramontana && echo *.log
acceso.log errores.log
operador@srv-tramontana:~$ echo '*.log'
*.log

En el primer caso echo recibió dos argumentos ya resueltos. En el segundo, las comillas impidieron el globbing y recibió el literal. Esta es la razón de que ls *.log y grep '.*\.log' fichero no se parezcan en nada: el primero pide archivos al shell, el segundo pide al programa que busque un patrón dentro del texto.

operador@srv-tramontana:~$ grep -c 'GET' *.log
acceso.log:298
errores.log:0

Aquí conviven las dos cosas: *.log lo expandió Bash (por eso grep sabe que hay dos ficheros y prefija el nombre), mientras que GET es el patrón que interpreta grep. Cuando un patrón es para el programa, va entre comillas simples. Siempre. Si escribes grep *.log fichero sin comillas y existe un acceso.log en el directorio, Bash lo sustituye y grep acaba buscando la cadena «acceso.log» dentro de errores.log. Un resultado plausible y erróneo.

Globbing Expresión regular
Lo procesa Bash el programa (grep, sed, awk…)
Actúa sobre nombres de archivo existentes cualquier texto
* significa cualquier secuencia de caracteres cero o más del elemento anterior
? significa exactamente un carácter cero o una aparición del anterior
Debe casar el nombre entero por defecto, cualquier parte de la línea
Si no casa nada el patrón se pasa literal el programa no devuelve resultados

Las dos últimas filas son sutiles y valen su peso en oro. Un glob debe casar el nombre completo, mientras que grep 'GET' casa cualquier línea que contenga esa cadena en cualquier posición.

  1. Globbing: los comodines del shell

Comodín Casa con Ejemplo en Tramontana
* cualquier secuencia, incluida la vacía *.log → acceso.log errores.log
? exactamente un carácter 3.2.? → 3.2.0 3.2.1
[abc] uno de los caracteres listados informe-[12].txt
[a-z] uno del rango [0-9]*.csv
[!abc] o [^abc] uno que no esté en la lista [!.]*
operador@srv-tramontana:~$ ls /opt/tramontana/releases/
3.1.0  3.2.0  3.2.1  3.3.0
operador@srv-tramontana:~$ ls -d /opt/tramontana/releases/3.2.*
/opt/tramontana/releases/3.2.0  /opt/tramontana/releases/3.2.1
operador@srv-tramontana:~$ ls -d /opt/tramontana/releases/3.[13].0
/opt/tramontana/releases/3.1.0  /opt/tramontana/releases/3.3.0

Tres propiedades del globbing que hay que tener presentes:

  • * no cruza las barras /. /opt/*/app no encuentra nada anidado a mayor profundidad; para eso está **, que verás en el apartado 4.
  • Los archivos ocultos no casan con *. echo * en tu $HOME no lista .bashrc. Es deliberado: evita que un rm * se lleve la configuración por delante.
  • El resultado va ordenado según la locale, con las consecuencias que ya conoces de 03-01.

La convención del curso —mirar con ls antes de un rm— es exactamente una comprobación de globbing: ejecutas el patrón con un comando inofensivo y ves qué habría recibido el peligroso.

operador@srv-tramontana:~$ ls /srv/tramontana/backups/temporales/*.tmp
/srv/tramontana/backups/temporales/export-1.tmp
/srv/tramontana/backups/temporales/export-2.tmp
operador@srv-tramontana:~$ rm /srv/tramontana/backups/temporales/*.tmp

  1. Clases POSIX y expansión de llaves

Dentro de los corchetes puedes usar clases con nombre, más legibles y correctas con acentos que un rango a mano:

Clase Equivale a
[[:digit:]] 0-9
[[:alpha:]] letras, incluidas las acentuadas de la locale
[[:alnum:]] letras y dígitos
[[:space:]] espacio, tabulador, salto de línea
[[:upper:]] / [[:lower:]] mayúsculas / minúsculas
[[:punct:]] signos de puntuación

Los dobles corchetes despistan: los externos son los del conjunto, los internos forman parte del nombre de la clase. Se combina con otros caracteres dentro del mismo conjunto: [[:digit:]-] casa un dígito o un guion.

La expansión de llaves no es globbing

{a,b} y {1..10} se parecen a los comodines y son otra cosa: generan texto, existan o no los archivos. Ocurre antes que el globbing.

operador@srv-tramontana:~$ echo informe-{enero,febrero,marzo}.txt
informe-enero.txt informe-febrero.txt informe-marzo.txt
operador@srv-tramontana:~$ echo /home/operador/trabajo/2026/{07,08,09}/{informes,datos}
/home/operador/trabajo/2026/07/informes /home/operador/trabajo/2026/07/datos
/home/operador/trabajo/2026/08/informes /home/operador/trabajo/2026/08/datos
/home/operador/trabajo/2026/09/informes /home/operador/trabajo/2026/09/datos

(La salida real va en una sola línea; aquí está partida para que se lea.) Esa estructura de directorios que ya tienes se creó exactamente así, con mkdir -p y una expansión de llaves. Los rangos aceptan paso: {1..10}, {a..e}, {0..30..5}.

El uso más rentable en el día a día es evitar repetir una ruta larga:

operador@srv-tramontana:~$ cp /etc/tramontana/app.conf{,.bak-$(date +%F)}
operador@srv-tramontana:~$ ls /etc/tramontana/
app.conf  app.conf.bak-2026-08-18

La llave {,.bak-...} se expande a dos argumentos: el original y el original con sufijo. Es la forma abreviada de la convención de copias del curso.

  1. Opciones de globbing: globstar, dotglob, nullglob, failglob

Se activan con shopt -s y se desactivan con shopt -u.

Opción Efecto
globstar habilita **, que sí cruza barras y recorre subdirectorios
dotglob hace que * incluya los archivos ocultos
nullglob si el patrón no casa nada, se expande a nada en vez de quedarse literal
failglob si el patrón no casa nada, el comando no se ejecuta y da error
nocaseglob globbing insensible a mayúsculas
extglob patrones extendidos: !(patrón), +(patrón), `@(a
operador@srv-tramontana:~$ shopt -s globstar
operador@srv-tramontana:~$ ls /opt/tramontana/releases/**/*.html
/opt/tramontana/releases/3.2.1/plantillas/confirmacion.html
/opt/tramontana/releases/3.2.1/plantillas/factura.html

Qué pasa por defecto cuando un patrón no casa nada

Este comportamiento sorprende y conviene entenderlo antes de sufrirlo. Por defecto, si un glob no encuentra nada, Bash lo deja tal cual y se lo pasa al comando como texto literal:

operador@srv-tramontana:~$ ls /var/log/tramontana/*.gz
ls: no se puede acceder a '/var/log/tramontana/*.gz': No existe el archivo

Fíjate en que el mensaje contiene el asterisco: ls recibió el patrón sin expandir e intentó abrir un archivo llamado literalmente *.gz. Con ls es inofensivo; con un comando destructivo, no tanto. Imagina rm /srv/tramontana/backups/temporales/*.tmp cuando ya no queda ningún .tmp: en el mejor caso da error, pero un comando que interpretara el argumento de otra forma podría hacer algo inesperado.

  • nullglob es lo que quieres cuando el patrón puede legítimamente no casar nada.
  • failglob es lo más seguro en trabajo interactivo: el comando aborta antes de ejecutarse.
operador@srv-tramontana:~$ shopt -s failglob
operador@srv-tramontana:~$ ls /var/log/tramontana/*.gz
bash: no coincidencias: /var/log/tramontana/*.gz

Ahora es Bash quien se niega, y ls no llegó a ejecutarse.

  1. Expresiones regulares: BRE, ERE y PCRE

Una expresión regular describe un conjunto de cadenas. El problema histórico es que hay tres dialectos y las herramientas de Unix no coinciden en cuál usan.

BRE (básica) ERE (extendida) PCRE (Perl)
Se usa en grep, sed grep -E, sed -E, awk grep -P
+ ? {} () ` ` hay que escaparlos: \+ \? funcionan directamente
\d \w \s no no sí
\b (borde de palabra) sí sí sí
Perezoso *? no no sí

Es decir: en BRE los paréntesis son literales y \\( es el metacarácter; en ERE es al revés. De ahí que la misma expresión dé resultados distintos con y sin -E:

operador@srv-tramontana:~$ grep -c 'GET\|POST' acceso.log
412
operador@srv-tramontana:~$ grep -Ec 'GET|POST' acceso.log
412
operador@srv-tramontana:~$ grep -c 'GET|POST' acceso.log
0

El tercero busca la cadena literal GET|POST, que no aparece nunca. Recomendación firme: usa siempre grep -E. Escribes menos barras, se lee mejor y es la sintaxis que comparten awk, egrep y casi cualquier lenguaje moderno. Reserva -P para lo que solo PCRE ofrece (\d, perezosos, lookahead), sabiendo que no está disponible en todas las máquinas.

  1. Los metacaracteres, uno a uno

Trabajamos sobre /var/log/tramontana/acceso.log, con este formato:

operador@srv-tramontana:~$ head -3 /var/log/tramontana/acceso.log
2026-08-18 09:14:02 GET /reservas/1012 200 ip=10.0.2.31 ms=48
2026-08-18 09:14:07 POST /reservas 201 ip=10.0.2.31 ms=134
2026-08-18 09:14:19 GET /casas/mas-figueres 200 ip=10.0.2.44 ms=22
Metacarácter Significa Ejemplo Casa
. un carácter cualquiera 2.6 2026, 216, 2x6
^ principio de línea ^2026-08-18 líneas de ese día
$ fin de línea ms=[0-9]+$ el campo final
[] uno del conjunto [45]0[0-9] 404, 500, 503
[^] uno fuera del conjunto [^0-9] cualquier no dígito
* cero o más del anterior ms=[0-9]* ms= y ms=134
+ uno o más del anterior ms=[0-9]+ solo ms=134
? cero o uno https? http, https
{n,m} entre n y m repeticiones [0-9]{3} exactamente tres dígitos
| alternancia GET|POST cualquiera de los dos
() agrupación (GET|POST) /reservas agrupa para la alternancia
\. punto literal 10\.0\.2\.15 esa IP y solo esa

La diferencia entre * y + es la que más falsos positivos genera: * acepta la ausencia total, así que grep 'ms=[0-9]*' casa incluso una línea con ms= vacío.

Los escapes solo existen en PCRE:

Escape Equivale a
\d [0-9]
\w [A-Za-z0-9_]
\s espacio en blanco
\D \W \S sus negaciones
\b borde de palabra (frontera entre \w y no-\w)

\b merece atención porque resuelve un problema constante. Buscar 200 en el log casa también con ms=200 o con /reservas/1200:

operador@srv-tramontana:~$ grep -c ' 200 ' acceso.log
331
operador@srv-tramontana:~$ grep -cE '\b200\b' acceso.log
338

Los espacios son más restrictivos que \b (que también aceptaría =200). En este caso lo correcto es lo primero, porque el código de estado va siempre rodeado de espacios. La opción -w de grep hace lo mismo que rodear todo el patrón de \b.

  1. Agrupación, alternancia y retrorreferencias

Los paréntesis hacen dos cosas: delimitan el alcance de un operador y capturan lo que casan para poder reutilizarlo.

operador@srv-tramontana:~$ grep -cE '^2026-08-18 09:(1[4-9]|2[0-9]):' acceso.log
57

Sin paréntesis, la alternancia se extendería hasta el final del patrón y 1[4-9]|2[0-9]: significaría «09:1[4-9]» o «2[0-9]:», que es otra cosa.

Una retrorreferencia \1 casa exactamente el mismo texto que capturó el primer grupo. Sirve para detectar repeticiones, que es algo que ningún patrón sin captura puede expresar:

operador@srv-tramontana:~$ grep -nE '(\b[a-z]+\b) \1' /home/operador/datos/casas.txt

Sin salida: no hay palabras duplicadas. Un uso real es localizar octetos repetidos o, en reservas.csv, detectar un separador doble:

operador@srv-tramontana:~$ grep -nE '(;)\1' /home/operador/datos/reservas.csv

También sin resultados, que es exactamente lo que queremos: ningún campo vacío por doble punto y coma. Una búsqueda sin salida es un resultado, no un fallo; conviene decirlo en voz alta porque cuesta interiorizarlo.

  1. Codicia: cuando la regex se lleva de más

Los cuantificadores *, + y {n,} son codiciosos: casan lo máximo posible. Es la causa del error clásico. Intentemos extraer solo la ruta de una línea de log con sed (que verás a fondo en 03-05; aquí solo como demostración):

operador@srv-tramontana:~$ echo '2026-08-18 09:14:02 GET /reservas/1012 200 ip=10.0.2.31 ms=48' \
    | sed -E 's/.*(\/.*) .*/\1/'
/reservas/1012 200 ip=10.0.2.31

Esperábamos /reservas/1012 y hemos obtenido tres campos. El motivo: .* dentro del grupo se comió todo lo que pudo mientras el patrón siguiera casando globalmente. La solución en ERE es prohibir el carácter que separa, en lugar de aceptar cualquiera:

operador@srv-tramontana:~$ echo '2026-08-18 09:14:02 GET /reservas/1012 200 ip=10.0.2.31 ms=48' \
    | sed -E 's/.*(\/[^ ]*) .*/\1/'
/reservas/1012

[^ ]* no puede cruzar un espacio, así que el grupo se detiene donde debe. [^X]* en vez de .* es la técnica que resuelve el 90 % de los problemas de codicia y funciona en todos los dialectos.

PCRE ofrece además cuantificadores perezosos, que casan lo mínimo: .*?. Con grep -oP '\/.*?\s' obtendrías el mismo resultado. Es cómodo, pero depende de -P, así que en scripts portables prefiere la clase negada.

  1. Método para construir una regex por pasos

Nadie escribe una expresión regular compleja de una vez. El método es incremental y siempre igual:

  1. Mira los datos reales. head -3 del fichero, no de memoria.
  2. Empieza por la parte más distintiva y comprueba que casa algo: grep -E 'ip=' acceso.log | head -3.
  3. Añade una pieza cada vez, verificando el recuento con -c después de cada añadido. Si el número cambia de forma inesperada, el problema está en lo último que añadiste.
  4. Usa -o para ver exactamente qué está casando, no la línea entera. Es la herramienta de depuración más útil que tiene grep.
  5. Comprueba también los falsos negativos: grep -vE 'patron' fichero | head te enseña lo que se te escapa. Suele ser más revelador que lo que sí casa.
  6. Solo cuando el patrón está validado, úsalo en algo que modifique datos.
operador@srv-tramontana:~$ grep -oE 'ip=[0-9.]+' acceso.log | head -3
ip=10.0.2.31
ip=10.0.2.31
ip=10.0.2.44

-o imprime solo la parte que casa, una por línea. Con eso ves de inmediato si tu patrón se está pasando o se está quedando corto.

  1. Regex prácticas del hilo conductor

Extraer direcciones IP. Una IP «bien hecha» exigiría validar que cada octeto es 0-255, lo cual produce un patrón ilegible. Para logs propios, con formato conocido, esto basta y se lee:

operador@srv-tramontana:~$ grep -oE 'ip=([0-9]{1,3}\.){3}[0-9]{1,3}' acceso.log | head -3
ip=10.0.2.31
ip=10.0.2.31
ip=10.0.2.44

([0-9]{1,3}\.){3} es «un grupo de uno a tres dígitos seguido de punto, repetido tres veces», más un último grupo sin punto. Los puntos van escapados: sin la barra casarían cualquier carácter.

Códigos de estado de error. Los 4xx y 5xx, que son los que interesan:

operador@srv-tramontana:~$ grep -cE ' [45][0-9]{2} ' acceso.log
23
operador@srv-tramontana:~$ grep -oE ' [45][0-9]{2} ' acceso.log | sort | uniq -c
      4  404
     14  500
      5  503

Los espacios que rodean el patrón evitan casar los tres primeros dígitos de un identificador de reserva.

Fechas ISO. [0-9]{4}-[0-9]{2}-[0-9]{2} es suficiente para un formato controlado. Si quieres restringir a meses válidos: [0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]). Ese nivel de rigor tiene sentido al validar entrada, no al buscar en tus propios logs.

Validar el formato de reservas.csv. El fichero tiene cabecera id;fecha;casa;huesped;noches;importe y 25 registros. Una línea válida es: un id de cuatro dígitos, una fecha ISO, un nombre de casa en minúsculas con guiones, un nombre de huésped, un número de noches y un importe decimal.

operador@srv-tramontana:~$ grep -cvE '^[0-9]{4};[0-9]{4}-[0-9]{2}-[0-9]{2};[a-z-]+;[^;]+;[0-9]+;[0-9]+\.[0-9]{2}$' \
    /home/operador/datos/reservas.csv
1

Solo una línea no valida: la cabecera, que efectivamente no cumple el formato de un registro. Eso confirma que los 25 registros son correctos. Fíjate en las tres decisiones de diseño del patrón: ^ y $ obligan a validar la línea entera (sin anclas, grep casaría cualquier fragmento y la validación no valdría nada); [^;]+ en el nombre del huésped acepta espacios y acentos pero no un punto y coma de más; y [0-9]+\.[0-9]{2} exige exactamente dos decimales en el importe.

Para ver cuál falla, grep -nvE '...' con -n te da el número de línea. Este patrón, guardado, es una comprobación de integridad que puedes ejecutar antes de cada importación.

Errores Comunes y Consejos

  • No entrecomillar el patrón de grep. Si contiene *, ? o [, Bash lo expande primero y buscas otra cosa. Comillas simples siempre.
  • Creer que * en regex es «cualquier cosa». En regex, * se aplica al elemento anterior. «Cualquier cosa» es .*.
  • Olvidar escapar el punto en una IP o en una extensión. 10.0.2.15 casa también 10x0y2z15. Escribe 10\.0\.2\.15.
  • Usar .* donde toca una clase negada. Si el resultado se lleva de más, cambia .* por [^delimitador]*.
  • Mezclar dialectos. Si escribes \d sin -P, grep busca la letra d literal y no avisa. Es un fallo silencioso.
  • Validar sin anclas. Un patrón de validación sin ^ y $ no valida nada.
  • Consejo: cuando un patrón no funcione, no lo reescribas entero. Quítale piezas hasta que casé algo y vuelve a añadirlas de una en una.
  • Consejo: grep --color=always -oE 'patron' es tu depurador. Y echo 'linea de prueba' | grep -E 'patron' te permite probar contra un caso inventado sin tocar el fichero real.

Ejercicios

Ejercicio 1. Sin usar find ni grep, lista con un único glob todos los directorios de release de la serie 3.2 en /opt/tramontana/releases/, y explica por qué 3.2* y 3.2.* no son equivalentes. Después crea con una sola orden la estructura /home/operador/trabajo/2026/{10,11,12}/{informes,datos}.

Ejercicio 2. Extrae de acceso.log todas las peticiones POST que hayan devuelto un código de error (4xx o 5xx), mostrando solo el método, la ruta y el código. Construye el patrón por pasos y muestra la verificación de cada paso.

Ejercicio 3. Marta te pide asegurar que reservas.csv no tenga importes mal formados antes de la importación mensual. Escribe una comprobación que detecte importes sin exactamente dos decimales, verifica que el fichero actual está limpio, y demuestra que tu patrón funciona probándolo contra una línea inventada que sí esté mal.

Soluciones

Solución 1.

operador@srv-tramontana:~$ ls -d /opt/tramontana/releases/3.2.*
/opt/tramontana/releases/3.2.0  /opt/tramontana/releases/3.2.1

3.2* casaría también un hipotético 3.20 o 3.25, porque * incluye la cadena vacía y no exige el punto. 3.2.* obliga a que haya un punto tras el 2, lo que en un esquema de versionado semántico es justo la diferencia entre «la serie 3.2» y «cualquier cosa que empiece por 3.2». Con cuatro releases el error no se ve; con cuarenta, sí.

operador@srv-tramontana:~$ mkdir -p /home/operador/trabajo/2026/{10,11,12}/{informes,datos}
operador@srv-tramontana:~$ ls /home/operador/trabajo/2026/
07  08  09  10  11  12

La expansión de llaves genera las seis rutas y mkdir -p crea los niveles intermedios. Nótese que esto no es globbing: funciona precisamente porque los directorios todavía no existen.

Solución 2. Paso a paso, verificando con -c tras cada añadido:

operador@srv-tramontana:~$ grep -cE 'POST' acceso.log
114
operador@srv-tramontana:~$ grep -cE 'POST /[^ ]+' acceso.log
114
operador@srv-tramontana:~$ grep -cE 'POST /[^ ]+ [45][0-9]{2}' acceso.log
18
operador@srv-tramontana:~$ grep -oE 'POST /[^ ]+ [45][0-9]{2}' acceso.log | sort | uniq -c | sort -rn
      9 POST /reservas 500
      5 POST /reservas/pago 503
      4 POST /reservas/pago 500

El primer paso confirma que hay POST. El segundo no cambia el recuento, lo que demuestra que todas las líneas POST tienen una ruta con el formato esperado: si hubiera bajado, tendríamos líneas malformadas. El tercero filtra por código de error: 18 de las 23 respuestas erróneas del log son peticiones POST. [^ ]+ en lugar de .* impide que la ruta se coma el resto de la línea, y [45][0-9]{2} casa cualquier 4xx o 5xx sin enumerarlos. -o recorta la salida a lo esencial y la tubería final agrupa; ese sort | uniq -c | sort -rn es el patrón que estudiarás a fondo en 03-05.

Solución 3.

operador@srv-tramontana:~$ grep -nvE ';[0-9]+\.[0-9]{2}$' /home/operador/datos/reservas.csv
1:id;fecha;casa;huesped;noches;importe

Solo la cabecera. Los 25 registros tienen el importe bien formado. Para excluir la cabecera del informe y quedarnos solo con errores reales:

operador@srv-tramontana:~$ tail -n +2 /home/operador/datos/reservas.csv \
    | grep -nvE ';[0-9]+\.[0-9]{2}$'
operador@srv-tramontana:~$ echo "codigo: $?"
codigo: 1

Sin salida y código 1: grep no encontró ninguna línea que incumpla, que es el resultado deseado. tail -n +2 empieza en la línea 2, saltándose la cabecera.

La parte importante del ejercicio es la última: un validador que nunca has visto fallar no está validado. Se prueba contra un caso malo conocido:

operador@srv-tramontana:~$ echo '1026;2026-08-19;can-ventos;Ana Puig;3;340.5' \
    | grep -nvE ';[0-9]+\.[0-9]{2}$'
1:1026;2026-08-19;can-ventos;Ana Puig;3;340.5

Detecta el importe con un solo decimal. Ahora sabes que el patrón discrimina de verdad y no está devolviendo «todo bien» por un error de sintaxis. Prueba también un caso bueno (340.50) y confirma que no lo marca: un validador debe fallar cuando toca y solo cuando toca.

Conclusión

Esta lección te ha dado dos lenguajes de patrones y, sobre todo, la frontera entre ellos.

  • El globbing lo hace Bash sobre nombres de archivo, antes de ejecutar nada. El comando recibe la lista ya resuelta y nunca ve el comodín. Lo compruebas con echo.
  • Las expresiones regulares las interpreta el programa sobre el texto que recibe, y por eso van entre comillas simples.
  • Dominas los comodines *, ?, [abc], [a-z], [!abc] y las clases POSIX, y sabes que * no cruza barras ni casa ocultos.
  • Distingues la expansión de llaves —que genera texto existan o no los archivos— del globbing, y usas {,.bak-$(date +%F)} para las copias de seguridad.
  • Controlas globstar, dotglob, nullglob y failglob, y sabes qué hace Bash por defecto cuando un patrón no casa: pasarlo literal.
  • Conoces la diferencia entre BRE, ERE y PCRE, y por qué la recomendación es grep -E.
  • Manejas los metacaracteres uno a uno, la agrupación, la alternancia y las retrorreferencias \1.
  • Entiendes la codicia y sabes que la solución portable es sustituir .* por una clase negada [^X]*.
  • Y tienes un método para construir patrones: datos reales, una pieza cada vez, -c para contar, -o para ver qué casa, -v para ver lo que se escapa, y probar el validador contra un caso malo antes de confiar en él.

En la siguiente lección, Búsqueda de Archivos y Contenido: find, locate y grep, estos patrones dejan de ser un ejercicio y se convierten en la interfaz de tres herramientas. find recorre el árbol de directorios aplicando criterios que incluyen globs; grep aplica expresiones regulares a millones de líneas en segundos; y locate responde al instante consultando una base de datos. Sabrás cuál usar en cada caso, cómo combinarlas con xargs sin que un nombre con espacios lo estropee todo, y cómo localizar en srv-tramontana los releases que hay que purgar, los .bak-* dispersos por el sistema y el fichero de configuración donde alguien dejó escrita una credencial.

Curso de Linux: De Principiante a Administrador de Sistemas

Módulo 1: Introducción a Linux

Módulo 2: Comandos Básicos de Linux

Módulo 3: Habilidades Avanzadas en la Línea de Comandos

Módulo 4: Scripting en Shell

Módulo 5: Administración del Sistema

Módulo 6: Redes y Seguridad

Módulo 7: Temas Avanzados

Módulo 8: Proyectos Prácticos

© Copyright 2026. Todos los derechos reservados