50% OFF Plus
--:--:--
¡Obtener!

Curso Bash

Bash
Bash
Actualizado: 10/05/2025

¡Desbloquea el curso completo!

IA
Ejercicios
Certificado
Entrar

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)

Guarda tu progreso

Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

Más de 25.000 desarrolladores ya confían en CertiDevs

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

Completa este curso de Bash y certifícate

Únete a nuestra plataforma de cursos de programación y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.

Asistente IA

Resuelve dudas al instante

Ejercicios

Practica con proyectos reales

Certificados

Valida tus conocimientos

Más de 25.000 desarrolladores ya se han certificado con CertiDevs

⭐⭐⭐⭐⭐
4.9/5 valoración