Bash scripting es, sin exageración, la habilidad más práctica y rentable que puedes adquirir como usuario o administrador de Linux. Con un simple archivo de texto, puedes automatizar copias de seguridad que se ejecuten cada noche, procesar miles de archivos en segundos, monitorizar servidores y crear herramientas personalizadas que ahorren horas de trabajo manual. Esta guía te lleva desde los fundamentos absolutos hasta la escritura de scripts profesionales con ejemplos reales, diagramas, ejercicios resueltos y un proyecto integrador completo que podrás adaptar a tu propio entorno de trabajo.
🐚 ¿Qué es Bash?
Bash (acrónimo recursivo de Bourne Again SHell) es el intérprete de comandos por defecto en la inmensa mayoría de distribuciones Linux y en macOS hasta Catalina (2019). Fue creado por Brian Fox en 1989 dentro del proyecto GNU de Richard Stallman, como un reemplazo libre y mejorado del Bourne Shell (sh) original de Unix. Hoy, cuando abres una terminal en Ubuntu, Debian, Mint, Fedora o CentOS, estás interactuando directamente con Bash.
Pero Bash no es solo un intérprete interactivo: es también un lenguaje de programación completo. Soporta variables, condicionales, bucles, funciones, arrays, redirecciones, pipes y expansiones. Un script de Bash es simplemente un archivo de texto plano que contiene una secuencia de estos comandos. En lugar de escribir cada instrucción manualmente en la terminal, los guardas en un archivo .sh, le das permisos de ejecución y lo lanzas cuando quieras. Es como crear una receta: escribes los pasos una vez y los repites cuantas veces necesites, de forma idéntica y sin errores humanos.
La potencia de Bash reside en su capacidad para combinar herramientas pequeñas y especializadas en flujos de trabajo complejos. Esta filosofía, heredada directamente de Unix, se conoce como el principio de composición: cada programa hace una sola cosa bien, y tú los conectas mediante pipes (|) para resolver problemas mayores. Un solo comando de Bash puede encadenar find, grep, sort, awk y sed en una línea que procese gigabytes de logs en pocos segundos.
La historia de Bash está profundamente entrelazada con la de Unix. En 1971, Ken Thompson escribió el primer shell de Unix, un programa minimalista que permitía ejecutar comandos uno a uno. En 1977, Stephen Bourne, trabajando en los laboratorios Bell de AT&T, creó el Bourne Shell (sh), que añadió capacidades de programación: variables, condicionales y bucles. Sin embargo, sh era software propietario de AT&T. Cuando Richard Stallman inició el proyecto GNU en 1983 para construir un sistema operativo completamente libre, necesitaba un shell libre. Brian Fox aceptó el reto y, tras varios años de desarrollo, anunció la primera versión beta de Bash en junio de 1989. El nombre — Bourne Again — es un juego de palabras con «born again» (renacer), señalando que era el renacimiento libre del Bourne Shell original.
| Característica | Bash | Python | PowerShell |
|---|---|---|---|
| Plataforma nativa | Linux/macOS | Multiplataforma | Windows |
| Ideal para | Tareas de sistema, archivos, pipes | Lógica compleja, APIs, datos | Administración Windows |
| Curva de aprendizaje | Baja para lo básico | Baja-media | Media |
| Uso en servidores | Ubicuo (96%+ servidores) | Muy extendido | Solo entornos Windows |
| Procesamiento de texto | Excelente (grep, sed, awk) | Bueno | Bueno |
| Manipulación de archivos | Nativo y rapidísimo | Requiere módulos (os, shutil) | Bueno (cmdlets) |
🚀 Tu primer script
Crear un script de Bash requiere solo tres pasos: crear el archivo, escribir los comandos y darle permisos de ejecución. No necesitas un IDE, un compilador ni librerías externas. Con cualquier editor de texto — desde nano en la terminal hasta VS Code — puedes empezar a programar inmediatamente.
La primera línea del script (#!/bin/bash) se denomina shebang (contracción de sharp-bang: almohadilla + exclamación). Es una directiva que le indica al kernel de Linux qué intérprete debe usarse para ejecutar el archivo. Sin ella, el sistema utilizará el shell por defecto del usuario, que podría no ser Bash — en macOS moderno, por ejemplo, el shell por defecto es Zsh. Por seguridad y portabilidad, incluye siempre el shebang como primera línea de tus scripts.
Una alternativa más portable es usar #!/usr/bin/env bash, que busca el ejecutable de Bash en el PATH del sistema. Esto es útil si Bash no está instalado exactamente en /bin/bash, algo que puede ocurrir en algunos entornos como FreeBSD o instalaciones personalizadas.
\r\n (retorno de carro + nueva línea), mientras que Linux solo usa \n. El carácter \r invisible puede provocar errores como bad interpreter: No such file or directory incluso cuando el shebang parece correcto. Solución: ejecuta dos2unix script.sh o usa sed -i 's/\r$//' script.sh para limpiar el archivo.
📦 Variables y tipos de datos
En Bash, las variables se crean simplemente asignando un valor — sin declarar tipos, sin palabras reservadas especiales. Internamente, todo en Bash es texto; incluso los números se almacenan como cadenas de caracteres, aunque Bash puede operar con ellos aritméticamente cuando se le indica. Esta simplicidad es a la vez su mayor fortaleza (rapidez para crear scripts) y su mayor trampa (errores sutiles si no se respetan las convenciones).
La regla más importante al asignar variables en Bash es: no dejes espacios alrededor del signo igual. Escribir nombre = "Ana" (con espacios) provocará un error, porque Bash interpretará nombre como un comando y = como su primer argumento. La forma correcta es siempre nombre="Ana", pegado y sin espacios.
Existen dos formas de expandir variables: $variable y ${variable}. La segunda forma, con llaves, es necesaria cuando la variable va seguida de caracteres que podrían confundir a Bash. Por ejemplo, "${archivo}_backup" funciona correctamente, mientras que "$archivo_backup" buscaría una variable llamada archivo_backup (que probablemente no existe). Como buena práctica, muchos programadores usan siempre las llaves para mayor claridad.
| Tipo de variable | Sintaxis | Ejemplo | Ámbito |
|---|---|---|---|
| Local (script) | VAR="valor" | RUTA="/tmp" | Solo el script actual |
| Exportada | export VAR="valor" | export PATH="..." | Script + procesos hijos |
| Local (función) | local var="valor" | local resultado=0 | Solo la función |
| Especial (readonly) | readonly VAR="valor" | readonly PI=3 | Constante inmutable |
| Array indexado | ARR=(a b c) | frutas=(manzana pera) | Acceso por índice: ${ARR[0]} |
| Array asociativo | declare -A M | M[clave]="valor" | Acceso por clave (Bash 4+) |
"$variable" con comillas dobles. Sin comillas, si una variable contiene espacios (como un nombre de archivo con espacios), Bash la dividirá en varias palabras causando errores inesperados. La excepción es dentro de [[ ]] y (( )), donde Bash no hace word splitting — pero incluso ahí, las comillas no hacen daño y hacen el código más legible.
🔀 Condicionales: if, elif, else, case
Los condicionales permiten que un script tome decisiones: ejecutar un bloque de código u otro en función de si se cumple una condición. Son esenciales para scripts que deben reaccionar al estado del sistema — por ejemplo, comprobar si un archivo existe antes de procesarlo, si un servicio está activo antes de reiniciarlo, o si hay espacio suficiente en disco antes de iniciar una copia de seguridad.
Bash ofrece dos formas de evaluar condiciones: el comando test (que se abrevia como [ ]) y la construcción moderna [[ ]]. La segunda es recomendable en casi todos los casos porque maneja mejor las cadenas con espacios, soporta expresiones regulares con =~, y permite operadores lógicos como && y || directamente dentro de la condición.
| Operador | Tipo | Significado | Ejemplo |
|---|---|---|---|
-f | Archivo | Existe y es fichero regular | [[ -f "/etc/passwd" ]] |
-d | Archivo | Existe y es directorio | [[ -d "/var/log" ]] |
-r / -w / -x | Archivo | Permisos lectura/escritura/ejecución | [[ -w "$archivo" ]] |
-z | Cadena | Cadena vacía (longitud cero) | [[ -z "$var" ]] |
-n | Cadena | Cadena no vacía | [[ -n "$var" ]] |
== / != | Cadena | Igual / Distinto | [[ "$a" == "$b" ]] |
-eq -ne -lt -le -gt -ge | Número | Comparaciones numéricas | [[ "$x" -gt 10 ]] |
🔁 Bucles: for, while, until
Los bucles son la estructura que transforma a Bash de un simple ejecutor de comandos en una herramienta de automatización real. Mientras que un condicional decide qué hacer, un bucle decide cuántas veces hacerlo. Son indispensables para procesar listas de archivos, recorrer líneas de un fichero, reintentar operaciones fallidas o monitorizar recursos del sistema de forma continua.
Bash ofrece tres tipos de bucle: for (itera sobre una lista), while (repite mientras la condición sea verdadera) y until (repite hasta que la condición sea verdadera). En la práctica, for y while cubren el 95% de los casos.
while read combinado con la sustitución de procesos: while IFS= read -r linea; do ... done < <(comando). A diferencia de comando | while read (que abre un subshell donde las variables se pierden), la sustitución de procesos con <() mantiene las variables accesibles tras el bucle. Es un detalle técnico que marca la diferencia entre un script amateur y uno profesional.
🧩 Funciones
Las funciones son bloques de código reutilizables que encapsulan una tarea específica. En scripts de más de 50 líneas, son absolutamente imprescindibles para mantener el código organizado, legible y mantenible. Una función en Bash se declara con nombre() { ... } y se invoca simplemente escribiendo su nombre, como si fuera un comando más del sistema.
A diferencia de la mayoría de lenguajes de programación, las funciones de Bash no declaran parámetros con nombre. Los argumentos se pasan por posición y se acceden dentro de la función con $1, $2, etc. — igual que los argumentos de un script completo. La variable $# contiene el número de argumentos recibidos, y $@ los contiene todos como una lista.
local para todas las variables dentro de funcioneslocal, las variables creadas dentro de una función son globales y pueden sobrescribir accidentalmente variables del mismo nombre en el ámbito principal. Esta es una de las fuentes de bugs más comunes en scripts Bash complejos. Declara siempre tus variables de función con local para aislar su ámbito.
📥 Entrada de usuario y argumentos
Un script profesional debe ser flexible: capaz de recibir datos tanto desde la línea de comandos (argumentos posicionales) como de forma interactiva (pidiendo entrada al usuario). Dominar ambas técnicas permite crear herramientas versátiles que se adaptan tanto al uso manual como a la automatización con cron o systemd timers.
🔍 Procesamiento de texto: grep, sed, awk
Si hay una habilidad que distingue a un usuario avanzado de Linux de un principiante, es el dominio de la tríada grep, sed y awk. Estas tres herramientas, todas con décadas de historia en el ecosistema Unix, permiten buscar, filtrar, transformar y analizar texto con una potencia y velocidad que difícilmente igualan los lenguajes de programación modernos cuando se trata de procesar archivos de log, configuraciones o datos tabulares directamente desde la terminal.
grep (Global Regular Expression Print) busca líneas que coincidan con un patrón. sed (Stream Editor) transforma texto sobre la marcha: reemplaza cadenas, elimina líneas, inserta contenido. awk es un lenguaje de procesamiento de campos orientado a columnas, ideal para datos estructurados en columnas separadas por espacios o caracteres delimitadores.
grep filtra, sed transforma y awk extrae columnas. Conectados con pipes, procesan miles de líneas en milisegundos.grep filtra, sed transforma y awk extrae columnas. Conectados con pipes, procesan miles de líneas en milisegundos.🐛 Depuración de scripts
Depurar scripts Bash puede ser frustrante si no conoces las herramientas disponibles. A diferencia de Python o Java, donde un error detiene la ejecución con un mensaje claro, Bash por defecto continúa ejecutando tras un error silencioso. Esta permisividad es peligrosa: un script de backup puede fallar en la copia pero seguir ejecutando la rotación, borrando archivos sin tener el respaldo. La solución es activar el modo estricto al inicio de todo script serio.
La opción -x (xtrace) es tu mejor aliada durante el desarrollo. Muestra cada comando justo antes de ejecutarlo, con todas las variables ya expandidas a sus valores reales. Esto te permite ver exactamente qué está haciendo tu script en cada paso. Puedes activarla para una sección específica con set -x al inicio y set +x al final, sin necesidad de depurar todo el script.
| Técnica | Comando | Cuándo usarla |
|---|---|---|
| Modo estricto | set -euo pipefail | Siempre, en todos tus scripts |
| Traza de ejecución | set -x / bash -x script.sh | Cuando necesitas ver qué se ejecuta |
| Verificar sintaxis | bash -n script.sh | Antes de ejecutar por primera vez |
| Linter estático | shellcheck script.sh | Siempre, como paso de calidad |
| Trap para errores | trap 'echo "Error L$LINENO"' ERR | Scripts largos con múltiples fallos posibles |
[ ] vs [[ ]], y decenas de malas prácticas. Puedes usarlo online o instalarlo con sudo apt install shellcheck. Ejecuta shellcheck script.sh antes de cada deploy — encontrarás bugs que ni una revisión manual detectaría.
✏️ Ejercicios resueltos
La programación solo se aprende practicando. Estos dos ejercicios están diseñados para integrar los conceptos vistos: variables, condicionales, bucles, funciones y procesamiento de texto. Intenta resolverlos por tu cuenta antes de consultar la solución.
Ejercicio 1: Renombrador masivo de archivos
Enunciado: Escribe un script que reciba un directorio como argumento y renombre todos los archivos .jpeg a .jpg, mostrando un resumen de cuántos archivos se renombraron.
Ver solución del Ejercicio 1
Ejercicio 2: Monitor de espacio en disco
Enunciado: Crea un script que compruebe el uso de disco de todas las particiones montadas. Si alguna supera el 80%, debe generar una alerta con el formato [ALERTA] /dev/sda1 → 87% (montado en /).
Ver solución del Ejercicio 2
🎯 Proyecto integrador: backup automático con rotación
Este proyecto combina todo lo aprendido en un script profesional que podrías desplegar hoy en un servidor de producción. El script comprime un directorio origen en un archivo .tar.gz con fecha, lo almacena en un directorio de destino, mantiene solo las últimas N copias (rotación automática) y genera un log de cada ejecución. Incluye validación de argumentos, manejo de errores con trap y funciones modulares.
crontab -e:0 3 * * * /home/ana/scripts/backup.sh /var/www /backup 7 2>&1
⚠️ Errores frecuentes y buenas prácticas
Incluso programadores experimentados cometen errores en Bash debido a su sintaxis particular. Estos son los errores que más tiempo consumen en depuración, junto con la solución correcta para cada uno. Aprenderlos te ahorrará incontables horas de frustración.
| Error | Código incorrecto | Código correcto | Explicación |
|---|---|---|---|
| Espacios en asignación | nombre = "Ana" | nombre="Ana" | Los espacios hacen que Bash trate nombre como comando |
| Variable sin comillas | rm $archivo | rm "$archivo" | Si tiene espacios, se divide en varias palabras |
| [ ] vs [[ ]] | [ $a == $b ] | [[ "$a" == "$b" ]] | [[ ]] no hace word splitting ni globbing |
| Comparar números | [[ 10 > 9 ]] | (( 10 > 9 )) | > en [[ ]] compara strings, no números |
| Command substitution | fecha=`date` | fecha=$(date) | Los backticks son obsoletos y no se anidan bien |
| Olvidar set -e | #!/bin/bash | #!/bin/bash | Sin -e, los errores se ignoran silenciosamente |
#!/bin/bash en la línea 1; (2) usa set -euo pipefail; (3) todas las variables están entrecomilladas; (4) valida los argumentos de entrada; (5) usa funciones para bloques reutilizables; (6) pasa ShellCheck sin advertencias; (7) tiene comentarios en las secciones no obvias; (8) los mensajes de error van a stderr (>&2).
❓ Preguntas frecuentes sobre Bash scripting desde cero: guía completa para automatizar Linux
Las dudas más comunes respondidas de forma clara y directa.
💬 Foro de discusión
¿Tienes dudas sobre Bash scripting desde cero: guía completa para automatizar Linux? Comparte tu pregunta con la comunidad.
Todavía no hay mensajes. ¡Sé el primero en participar!
🎓 ¿Se puede aprender Linux con un curso bonificado por FUNDAE?
Sí. Todo lo que estás practicando en la terminal se puede llevar a un curso tutorizado de Bash y Shell Script bonificable al 100 % por FUNDAE si trabajas por cuenta ajena en España. Ciberaula es centro acreditado desde 1997.
Bash Scripting y Terminal Linux: Automatización de Sistemas (70 h) →
También te puede encajar: Administración de Sistemas Linux y Shell Script para Empresas → · Administración de Servidores Linux para Empresas: de Cero a Nivel Avanzado →
Ver todos los cursos de Linux bonificados del catálogo → · Ciberaula · Centro acreditado FUNDAE (Reg. 99000171) · 91 530 33 87 · admision@ciberaula.com