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
- Quién expande qué: el shell antes, el programa después
- Globbing: los comodines del shell
- Clases POSIX y expansión de llaves
- Opciones de globbing: globstar, dotglob, nullglob, failglob
- Expresiones regulares: BRE, ERE y PCRE
- Los metacaracteres, uno a uno
- Agrupación, alternancia y retrorreferencias
- Codicia: cuando la regex se lleva de más
- Método para construir una regex por pasos
- Regex prácticas del hilo conductor
- 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'
*.logEn 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.
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.
- 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.0Tres propiedades del globbing que hay que tener presentes:
*no cruza las barras/./opt/*/appno 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$HOMEno lista.bashrc. Es deliberado: evita que unrm *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
- 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-18La 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.
- 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.htmlQué 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 archivoFí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.
nullglobes lo que quieres cuando el patrón puede legítimamente no casar nada.failglobes 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/*.gzAhora es Bash quien se niega, y ls no llegó a ejecutarse.
- 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
0El 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.
- 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
338Los 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.
- 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.
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:
Sin salida: no hay palabras duplicadas. Un uso real es localizar octetos repetidos o, en reservas.csv, detectar un separador doble:
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.
- 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.31Esperá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.
- 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:
- Mira los datos reales.
head -3del fichero, no de memoria. - Empieza por la parte más distintiva y comprueba que casa algo:
grep -E 'ip=' acceso.log | head -3. - Añade una pieza cada vez, verificando el recuento con
-cdespués de cada añadido. Si el número cambia de forma inesperada, el problema está en lo último que añadiste. - Usa
-opara ver exactamente qué está casando, no la línea entera. Es la herramienta de depuración más útil que tienegrep. - Comprueba también los falsos negativos:
grep -vE 'patron' fichero | headte enseña lo que se te escapa. Suele ser más revelador que lo que sí casa. - 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.
- 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 503Los 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
1Solo 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.15casa también10x0y2z15. Escribe10\.0\.2\.15. - Usar
.*donde toca una clase negada. Si el resultado se lleva de más, cambia.*por[^delimitador]*. - Mezclar dialectos. Si escribes
\dsin-P,grepbusca la letradliteral 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. Yecho '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.13.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 12La 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 500El 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;importeSolo 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: 1Sin 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.5Detecta 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,nullglobyfailglob, 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,
-cpara contar,-opara ver qué casa,-vpara 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
- ¿Qué es Linux?
- Historia de Linux
- Distribuciones de Linux
- Instalando Linux
- Primer Contacto con el Sistema
- Estructura del Sistema de Archivos de Linux
Módulo 2: Comandos Básicos de Linux
- Introducción a la Línea de Comandos
- Obtener Ayuda y Documentación del Sistema
- Navegando el Sistema de Archivos
- Operaciones con Archivos y Directorios
- Visualización y Edición de Archivos
- Enlaces Duros y Simbólicos
- Permisos y Propiedad de Archivos
Módulo 3: Habilidades Avanzadas en la Línea de Comandos
- El Entorno del Shell: Variables, Alias e Historial
- Uso de Comodines y Expresiones Regulares
- Búsqueda de Archivos y Contenido: find, locate y grep
- Tuberías y Redirección
- Procesamiento de Texto: cut, sort, uniq, sed y awk
- Gestión de Procesos
- Programación de Tareas con Cron
- Comandos de Redes
Módulo 4: Scripting en Shell
- Introducción al Scripting en Shell
- Variables y Tipos de Datos
- Entrada, Salida y Argumentos de un Script
- Estructuras de Control
- Funciones y Librerías
- Depuración y Manejo de Errores
- Scripts de Producción: Buenas Prácticas
Módulo 5: Administración del Sistema
- Gestión de Usuarios y Grupos
- sudo y Permisos Especiales
- Gestión de Paquetes
- Gestión de Discos
- systemd y la Gestión de Servicios
- Registros del Sistema: journald y syslog
- Monitoreo del Sistema y Optimización del Rendimiento
- Respaldo y Restauración
Módulo 6: Redes y Seguridad
- Configuración de Redes
- SSH y Acceso Remoto
- Firewall y Seguridad Perimetral
- Sistemas de Detección de Intrusos
- Gestión de Secretos y Certificados TLS
- Asegurando Sistemas Linux
Módulo 7: Temas Avanzados
- El Proceso de Arranque y la Recuperación del Sistema
- Diagnóstico Avanzado: strace, perf y eBPF
- Optimización del Kernel de Linux
- Virtualización con Linux
- Contenedores de Linux y Docker
- Automatización con Ansible
- Alta Disponibilidad y Balanceo de Carga
