Descripción del curso Bash
Bash (Bourne Again SHell) es un intérprete de comandos y lenguaje de scripting que actúa como interfaz entre el usuario y el sistema operativo Unix/Linux. Desarrollada como parte del Proyecto GNU, es una evolución mejorada de la shell Bourne original (sh) que incorpora características de otras shells como Korn shell (ksh) y C shell (csh).
Como shell predeterminada en la mayoría de distribuciones Linux, macOS (hasta Catalina) y disponible en Windows a través de WSL (Windows Subsystem for Linux), Bash se ha convertido en una herramienta esencial para administradores de sistemas, desarrolladores y usuarios avanzados.
Cuando abres una terminal, generalmente interactúas con Bash a través de un prompt que muestra información como tu nombre de usuario, el host y el directorio actual:
usuario@host:~/documentos$
El símbolo $
indica un usuario regular, mientras que #
aparece cuando trabajas como superusuario (root).
Para verificar qué shell estás utilizando:
echo $SHELL
Para conocer la versión de Bash:
bash --version
Sintaxis básica
La estructura general de un comando en Bash es:
comando [opciones] [argumentos]
Por ejemplo:
ls -la /home/usuario
Donde:
ls
es el comando que lista archivos-la
son las opciones (l: formato largo, a: mostrar archivos ocultos)/home/usuario
es el argumento (el directorio a listar)
Puedes ejecutar varios comandos en una misma línea utilizando diferentes separadores:
Punto y coma (;
): Ejecuta los comandos secuencialmente independientemente del resultado.
echo "Primero"; echo "Segundo"
AND lógico (&&
): El segundo comando se ejecuta solo si el primero tiene éxito.
mkdir directorio && cd directorio
OR lógico (||
): El segundo comando se ejecuta solo si el primero falla.
grep "patrón" archivo.txt || echo "Patrón no encontrado"
Los comentarios en Bash comienzan con el símbolo #
:
# Este es un comentario
echo "Hola mundo" # Este es un comentario al final de una línea
Variables
En Bash, las variables se declaran sin especificar tipo:
nombre="Ana"
edad=25
es_estudiante=true
Reglas importantes:
- No debe haber espacios antes ni después del signo igual (
=
) - Los nombres de variables pueden contener letras, números y guiones bajos, pero no pueden comenzar con un número
- Las variables son sensibles a mayúsculas y minúsculas
Para acceder al valor de una variable, se usa el prefijo $
:
echo "Hola, $nombre. Tienes $edad años."
También puedes usar la forma ${variable}
, que es útil para desambiguar:
echo "Hola, ${nombre}s" # Para mostrar "Hola, Anas"
Bash proporciona varias variables especiales:
$0
: Nombre del script$1
,$2
, etc.: Argumentos posicionales$#
: Número de argumentos$@
: Todos los argumentos como palabras separadas$*
: Todos los argumentos como una sola palabra$?
: Código de salida del último comando (0 indica éxito)$$
: PID (Process ID) de la shell actual$!
: PID del último proceso en segundo plano
Las variables de entorno afectan el comportamiento del sistema y los programas:
echo $HOME # Directorio principal del usuario
echo $PATH # Rutas donde se buscan ejecutables
echo $USER # Nombre de usuario actual
Para crear una variable de entorno que esté disponible para los procesos hijo:
export MI_VARIABLE="valor"
Arrays (matrices)
Bash soporta arrays indexados (desde 0) y, en versiones más recientes, arrays asociativos.
Arrays indexados:
# Declaración e inicialización
frutas=("manzana" "naranja" "plátano")
# Acceso a elementos
echo ${frutas[0]} # manzana
# Añadir elemento
frutas+=("uva")
# Mostrar todos los elementos
echo ${frutas[@]}
# Número de elementos
echo ${#frutas[@]}
Arrays asociativos (desde Bash 4.0):
# Declaración (requerida para arrays asociativos)
declare -A colores
# Asignación
colores[rojo]="#FF0000"
colores[verde]="#00FF00"
colores[azul]="#0000FF"
# Acceso
echo ${colores[rojo]}
# Todas las claves
echo ${!colores[@]}
Operadores
Para realizar operaciones aritméticas, Bash ofrece varias sintaxis:
# La forma recomendada
resultado=$((5 + 3))
Operadores disponibles:
+
: Suma-
: Resta*
: Multiplicación/
: División (entera)%
: Módulo (resto)**
: Exponenciación
echo $((10 + 5)) # 15
echo $((10 - 5)) # 5
echo $((10 * 5)) # 50
echo $((10 / 3)) # 3 (división entera)
echo $((10 % 3)) # 1 (resto)
echo $((2 ** 3)) # 8 (potencia)
Para incremento y decremento:
((variable++)) # Incremento después de usar
((++variable)) # Incremento antes de usar
Operadores de comparación numérica (dentro de (( ))
):
if ((a < b)); then
echo "a es menor que b"
fi
==
: Igual!=
: No igual<
: Menor que<=
: Menor o igual>
: Mayor que>=
: Mayor o igual
Operadores de comparación de cadenas (dentro de [[ ]]
):
if [[ "$a" == "$b" ]]; then
echo "Las cadenas son iguales"
fi
==
: Igual!=
: No igual<
: Menor en orden lexicográfico>
: Mayor en orden lexicográfico-z
: Verdadero si la cadena está vacía-n
: Verdadero si la cadena no está vacía
Operadores para comprobación de archivos:
if [[ -f "$archivo" ]]; then
echo "Es un archivo regular"
fi
-f
: Es un archivo regular-d
: Es un directorio-e
: Existe (archivo o directorio)-r
: Tiene permiso de lectura-w
: Tiene permiso de escritura-x
: Tiene permiso de ejecución-s
: Tamaño mayor que cero-L
: Es un enlace simbólico
Estructuras de control
La estructura if
:
if [[ condición ]]; then
# comandos
elif [[ otra_condición ]]; then
# otros comandos
else
# comandos por defecto
fi
Nota: Los espacios dentro de [[ ]]
son importantes.
Estructura case
:
case $variable in
patrón1)
# comandos
;;
patrón2|patrón3)
# comandos para múltiples patrones
;;
*)
# caso por defecto
;;
esac
Bucle for
(varios formatos):
# Iteración sobre lista
for nombre in Juan Ana Pedro; do
echo "Hola, $nombre"
done
# Rango numérico
for i in {1..5}; do
echo "Número: $i"
done
# Sintaxis estilo C
for ((i=0; i<5; i++)); do
echo "Iteración $i"
done
# Iteración sobre archivos
for archivo in *.txt; do
echo "Procesando $archivo"
done
Bucle while
:
contador=0
while [[ $contador -lt 5 ]]; do
echo "Contador: $contador"
((contador++))
done
Bucle until
(continúa hasta que la condición sea verdadera):
contador=0
until [[ $contador -ge 5 ]]; do
echo "Contador: $contador"
((contador++))
done
Control de bucles:
for i in {1..10}; do
if [[ $i -eq 5 ]]; then
continue # Salta a la siguiente iteración
fi
if [[ $i -eq 8 ]]; then
break # Sale del bucle
fi
echo "Número: $i"
done
Funciones
Definición y llamada de funciones:
# Definición con la palabra clave "function"
function saludar {
echo "Hola, $1!"
}
# Forma alternativa
saludar_alternativa() {
echo "Hola, $1!"
}
# Llamada
saludar "Juan"
Las funciones en Bash no devuelven valores como en otros lenguajes, pero existen varias técnicas:
# Usando código de salida
function es_par {
if (( $1 % 2 == 0 )); then
return 0 # verdadero en Bash
else
return 1 # falso en Bash
fi
}
# Verificación
if es_par 4; then
echo "Es par"
fi
# Usando echo y captura
function suma {
echo $(( $1 + $2 ))
}
resultado=$(suma 5 3)
echo "La suma es: $resultado"
Las variables en Bash son globales por defecto, a menos que se declaren como local
:
variable_global="Global"
function prueba_alcance {
local variable_local="Local"
echo "Dentro: global=$variable_global, local=$variable_local"
}
prueba_alcance
echo "Fuera: global=$variable_global"
echo "Intentando acceder a variable local: $variable_local" # Será vacío
Entrada y salida
Para obtener entrada del usuario:
# Lectura básica
echo "Introduce tu nombre:"
read nombre
echo "Hola, $nombre"
# Con prompt incorporado
read -p "Introduce tu edad: " edad
echo "Tienes $edad años"
# Entrada silenciosa (para contraseñas)
read -sp "Contraseña: " password
echo -e "\nContraseña recibida"
Redirección de entrada/salida:
# Redirigir salida estándar a archivo (sobrescribir)
comando > archivo.txt
# Redirigir y anexar salida estándar a archivo
comando >> archivo.txt
# Redirigir error estándar
comando 2> errores.log
# Redirigir ambos (salida y error) a archivos diferentes
comando > salida.txt 2> errores.log
# Redirigir ambos al mismo archivo
comando > archivo.txt 2>&1
# Forma moderna para redirigir ambos
comando &> archivo.txt
# Descartar salida
comando > /dev/null
Las tuberías (pipes) permiten conectar la salida de un comando con la entrada de otro:
# Filtrar resultados
ls -la | grep ".txt"
# Encadenar múltiples comandos
cat archivo.txt | tr '[:lower:]' '[:upper:]' | sort > resultado.txt
# Contar líneas/palabras/caracteres
cat archivo.txt | wc -l
Procesamiento de archivos
Lectura de archivos:
# Línea por línea
while IFS= read -r linea; do
echo "Leído: $linea"
done < archivo.txt
# Todo el archivo de una vez
contenido=$(<archivo.txt)
echo "$contenido"
# Usando IFS para CSV
while IFS=, read -r campo1 campo2 campo3; do
echo "Campo 1: $campo1, Campo 2: $campo2, Campo 3: $campo3"
done < datos.csv
Escritura en archivos:
# Sobrescribir
echo "Nuevo contenido" > archivo.txt
# Añadir
echo "Contenido adicional" >> archivo.txt
# Usando redirección heredoc
cat << EOF > archivo.txt
Línea 1
Línea 2
Línea con variable: $variable
EOF
# Here-doc con variables no expandidas
cat << 'EOF' > archivo.txt
Línea con $variable sin expandir
EOF
Expansiones y sustituciones
Expansión de variables:
nombre="Juan"
echo "${nombre}" # Expansión simple
echo "${nombre}s" # Desambiguación
echo "${nombre:-defecto}" # Valor por defecto si no existe o está vacía
echo "${nombre:=defecto}" # Asignar valor por defecto si no existe o está vacía
echo "${nombre:+alternativo}" # Valor alternativo si existe y no está vacía
echo "${nombre:?mensaje}" # Error con mensaje si no existe o está vacía
Manipulación de cadenas:
cadena="Hola Mundo"
echo "${cadena:5}" # "Mundo" (a partir del índice 5)
echo "${cadena:0:4}" # "Hola" (4 caracteres desde el índice 0)
echo "${#cadena}" # 10 (longitud de la cadena)
# Manipulación de patrones
archivo="imagen.jpg"
echo "${archivo%.jpg}" # "imagen" (elimina .jpg del final)
echo "${archivo#imagen}" # ".jpg" (elimina imagen del principio)
# Sustitución
echo "${cadena/Mundo/Amigo}" # "Hola Amigo" (reemplaza primera coincidencia)
echo "${cadena//o/O}" # "HOla MundO" (reemplaza todas las coincidencias)
# Transformaciones (Bash 4.0+)
echo "${cadena^^}" # "HOLA MUNDO" (todo a mayúsculas)
echo "${cadena,,}" # "hola mundo" (todo a minúsculas)
Expansión de comandos:
# Sintaxis moderna (recomendada)
fecha_actual=$(date)
echo "La fecha actual es: $fecha_actual"
# Anidamiento
echo "Archivos encontrados: $(find . -name "*.txt" | wc -l)"
# Cálculo aritmético
echo "Resultado: $((5 * $(wc -l < archivo.txt)))"
Expansión de llaves:
# Generación de secuencias
echo {1..5} # "1 2 3 4 5"
echo {a..e} # "a b c d e"
echo {1..10..2} # "1 3 5 7 9" (paso de 2)
# Combinaciones
echo file{1,2,3}.txt # "file1.txt file2.txt file3.txt"
echo archivo.{jpg,png,gif} # "archivo.jpg archivo.png archivo.gif"
# Anidamiento
echo {a,b}{1,2} # "a1 a2 b1 b2"
Control de procesos
Ejecución en segundo plano:
# Ejecutar comando en segundo plano
comando &
# Verificar trabajos en ejecución
jobs
# Traer trabajo a primer plano
fg %1
# Enviar trabajo a segundo plano (después de Ctrl+Z)
bg %1
Gestión de procesos:
# Listar procesos
ps aux
ps -ef
# Filtrar procesos
ps aux | grep "firefox"
# Matar proceso por PID
kill 1234
# Forzar terminación
kill -9 1234
# Matar proceso por nombre
pkill firefox
killall firefox
Ejecución condicional y señales:
# Capturar señal Ctrl+C (SIGINT)
trap "echo 'Operación cancelada'; exit" SIGINT
# Limpiar al salir
trap "echo 'Limpiando...'; rm -f /tmp/archivo_temp.$$" EXIT
# Ignorar señal
trap "" SIGTERM
# Restablecer comportamiento predeterminado
trap - SIGINT
Scripting avanzado
Estructura de un script:
#!/bin/bash
# Descripción: Este script hace X
# Autor: Tu nombre
# Fecha: YYYY-MM-DD
# Configuración
set -euo pipefail
# Constantes
readonly CONFIG_FILE="/etc/miapp.conf"
readonly MAX_INTENTOS=3
# Funciones
function log_mensaje() {
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
echo "[$timestamp] $1"
}
# Código principal
log_mensaje "Iniciando script"
# ... resto del script
log_mensaje "Script completado"
exit 0
Opciones de línea de comandos:
while getopts ":f:v:h" opt; do
case $opt in
f)
archivo="$OPTARG"
;;
v)
nivel_verbosidad="$OPTARG"
;;
h)
echo "Uso: $0 [-f archivo] [-v nivel] [-h]"
exit 0
;;
\?)
echo "Opción inválida: -$OPTARG" >&2
exit 1
;;
:)
echo "La opción -$OPTARG requiere un argumento." >&2
exit 1
;;
esac
done
Manejo de errores:
# Salir al primer error
set -e
# Detectar uso de variables no definidas
set -u
# Propagar errores en tuberías
set -o pipefail
# Todo junto (recomendado para scripts robustos)
set -euo pipefail
# Función de error
function error_salida() {
local linea=$1
local mensaje=$2
echo "Error en línea $linea: $mensaje" >&2
exit 1
}
# Usar trap para capturar errores con información de línea
trap 'error_salida ${LINENO} "$BASH_COMMAND"' ERR
Inclusión de archivos:
# Cargar funciones o variables de otro archivo
source funciones.sh
# o
. funciones.sh
# Verificar si el archivo existe antes de incluirlo
if [[ -f config.sh ]]; then
source config.sh
else
echo "Archivo de configuración no encontrado" >&2
exit 1
fi
Buenas prácticas
Seguridad:
# Comillas en variables para evitar problemas con espacios
echo "Procesando archivo: \"$archivo\""
# Validar entrada antes de usar
if [[ ! $numero =~ ^[0-9]+$ ]]; then
echo "Error: '$numero' no es un número válido" >&2
exit 1
fi
# Evitar inyección de comandos
archivo_seguro=$(printf '%q' "$nombre_archivo")
eval "cp $archivo_seguro /destino/"
Portabilidad:
# Usar shebang con env para mayor portabilidad
#!/usr/bin/env bash
# Comprobar disponibilidad de comandos
if ! command -v jq &> /dev/null; then
echo "Error: jq no está instalado" >&2
exit 1
fi
# Establecer ruta predeterminada para comandos
PATH="/usr/local/bin:/usr/bin:/bin"
Eficiencia:
# Evitar llamadas externas innecesarias
if [[ "$cadena" == *"subcadena"* ]]; then # Expansión de patrón nativa
echo "Contiene subcadena"
fi
# Uso de parámetros nativos
echo "${#cadena}" # en lugar de echo "$cadena" | wc -c
# Usar mapeos internos para transformaciones simples
echo "${cadena^^}" # en lugar de echo "$cadena" | tr '[:lower:]' '[:upper:]'
Depuración:
# Mostrar comandos al ejecutarse
set -x
comando1
comando2
set +x
# Solo activar depuración si se establece una variable
if [[ "${DEBUG:-}" == "true" ]]; then
set -x
fi
# Ejecutar script con depuración
bash -x script.sh
Lecciones y tutoriales de Bash
Ejercicios de programación de Bash
Módulos del curso
Explora todos los módulos disponibles en este curso de Bash
Explorar más tecnologías
Descubre más tecnologías de programación y desarrollo de software

Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Bash es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.