Categoría: Scripting

  • 1. Introducción al Shell y al Scripting

    1. Introducción al Shell y al Scripting

    1. ¿Qué es un Shell?

    Un shell es un programa que permite al usuario comunicarse con el sistema operativo. Interpreta los comandos que escribimos y envía instrucciones al sistema para que las ejecute.

    En sistemas GNU/Linux existen varios shells. Algunos de los más conocidos son:

    • Bash (Bourne Again SHell): el más utilizado en Linux, objetivo de este curso.
    • Zsh: muy usado en macOS y por usuarios que personalizan el terminal.
    • Fish: ofrece funcionalidades más modernas (autocompletado avanzado, etc.).
    • Dash: es un shell muy minimalista usado en muchos sistemas para scripts del sistema.

    En nuestro caso trabajaremos con Bash porque es el estándar en Ubuntu y muy común en servidores Linux.


    2. ¿Qué es Bash?

    Bash es tanto un intérprete de comandos como un lenguaje de scripting. Esto significa que:

    • Podemos usarlo interactivamente, escribiendo comandos en la terminal.
    • Podemos guardar comandos en un archivo para ejecutarlos como un programa.

    Gracias a esto, Bash es muy útil para:

    • Automatizar tareas repetitivas.
    • Administrar sistemas Linux.
    • Crear herramientas personalizadas.
    • Trabajar en entornos DevOps y ciberseguridad.

    3. ¿Qué es un Script?

    Un script es un archivo que contiene una secuencia de comandos. En lugar de escribirlos uno a uno en la terminal, los agrupamos para que se ejecuten automáticamente.

    Un ejemplo básico de script sería:

    
    
    
    
    
    echo "Hola, mundo!"
    echo "Este es mi primer script."
    

    Un script se ejecuta de principio a fin, permitiendo automatizar procesos como:

    • Copias de seguridad.
    • Instalación de software.
    • Monitorización del sistema.
    • Generación de informes.
    • Gestión de archivos.

    4. ¿Por qué aprender Bash?

    Dominar Bash abre la puerta a muchas áreas técnicas, como:

    • Administración de sistemas y servidores.
    • DevOps y automatización CI/CD.
    • Ciberseguridad (análisis, auditorías, automatización).
    • Ciencia de datos (procesamiento rápido de archivos).
    • Desarrollo backend y despliegues.

    Además:

    • Está disponible por defecto en la mayoría de sistemas Linux.
    • Funciona en entornos gráficos y no gráficos.
    • Requiere pocos recursos.
    • Es sencillo de empezar, pero muy potente en niveles avanzados.

    5. Rutas, Directorios y Comandos Básicos

    Para trabajar con Bash necesitamos movernos entre carpetas y ejecutar comandos.

    Algunos comandos básicos que ya deberías conocer o aprender ahora son:

    • pwd — muestra la ruta actual (“print working directory”)
    • ls — lista los archivos en el directorio
    • cd — cambia de directorio
    • mkdir — crea una carpeta
    • touch — crea un archivo vacío
    • cat — muestra el contenido de un archivo
    • rm, cp, mv — borrar, copiar y mover archivos
    • man comando — ver el manual de un comando

    Estos comandos se usan tanto en modo interactivo como dentro de scripts.


    6. Tipos de Rutas: Absolutas y Relativas

    En Linux todo comienza en /, llamado root del sistema.

    Existen dos tipos de rutas:

    Ruta absoluta: empieza desde la raíz del sistema.
    Ejemplos:

    
    
    
    
    
    /home/usuario/documentos
    /etc
    /var/log
    

    Ruta relativa: depende de la ruta en la que estés.
    Ejemplos:

    
    
    
    
    
    ./miarchivo
    ../otra_carpeta
    scripts/
    

    Conocer esto es importante para escribir scripts reproducibles.


    7. Primer Script: Hola Mundo

    Vamos a crear un script sencillo para entender el proceso.

    1. Crea un archivo:
    
    
    
    
    
    nano hola.sh
    
    1. Escribe dentro:
    
    
    
    
    
    #!/bin/bash
    echo "Hola mundo desde Bash"
    
    1. Guarda y sal del editor.
    2. Dale permisos de ejecución:
    
    
    
    
    
    chmod +x hola.sh
    
    1. Ejecútalo:
    
    
    
    
    
    ./hola.sh
    

    Si aparece el texto en pantalla, lo has hecho bien.


    8. ¿Qué es el Shebang?

    La primera línea del script se llama shebang, y sirve para indicar qué intérprete debe ejecutar el archivo.

    Ejemplos:

    • #!/bin/bash → interpreta el script con Bash
    • #!/usr/bin/python3 → interpreta con Python 3
    • #!/bin/sh → shell compatible POSIX

    Si no pones shebang, el sistema usará el intérprete por defecto, lo que puede causar comportamientos inesperados.


    9. Errores habituales del Principiante

    Es normal ver errores como:

    • permission denied → falta ejecutar chmod +x script.sh
    • command not found → se ejecuta con un shell distinto o está mal escrito
    • no such file or directory → falta ruta, archivo o extensión

    También es común olvidar que Linux diferencia mayúsculas y minúsculas:

    
    
    
    
    
    hola.sh ≠ Hola.sh ≠ HOLA.SH
    

    Ejercicios propuestos

    Ejercicio 1: Abrir la terminal y ejecutar los comandos:

    • pwd
    • ls
    • cd hacia diferentes carpetas
    • Crear y borrar archivos con touch y rm

    Ejercicio 2: Crear un script llamado presentacion.sh que muestre:

    • Tu nombre
    • El día actual
    • Tu directorio de trabajo

    Ejemplo de salida esperada:

    
    
    
    
    
    Mi nombre es Juan Pérez
    Hoy es 2026-01-10
    Estoy trabajando en /home/juan
    

    Ejercicio 3: Crear un script que liste los archivos del directorio /etc y guarde el resultado en etc-listado.txt.


    Soluciones

    Ejercicio 1 — Solución

    Enunciado:
    Abrir la terminal y ejecutar los comandos:

    • pwd
    • ls
    • cd hacia diferentes carpetas
    • Crear y borrar archivos con touch y rm

    📌 Solución / Resultado esperado:

    1. Mostrar la ruta actual:
    
    
    
    
    
    pwd
    

    Ejemplo de salida:

    
    
    
    
    
    /home/alumno
    
    1. Listar archivos del directorio actual:
    
    
    
    
    
    ls
    

    Salida posible:

    
    
    
    
    
    Documentos  Descargas  Imágenes
    
    1. Cambiar de directorio:
    
    
    
    
    
    cd Documentos
    pwd
    

    Ejemplo:

    
    
    
    
    
    /home/alumno/Documentos
    

    Luego volver al home:

    
    
    
    
    
    cd ~
    pwd
    
    1. Crear y borrar archivos:

    Crear un archivo vacío:

    
    
    
    
    
    touch prueba.txt
    

    Verificar:

    
    
    
    
    
    ls
    

    Debería aparecer prueba.txt.

    Borrar el archivo:

    
    
    
    
    
    rm prueba.txt
    

    Ejercicio 2 — Solución

    Enunciado:
    Crear un script presentacion.sh que muestre:

    • Tu nombre
    • El día actual
    • Tu directorio de trabajo

    Ejemplo de salida esperada:

    
    
    
    
    
    Mi nombre es Juan Pérez
    Hoy es 2026-01-10
    Estoy trabajando en /home/juan
    

    💡 Solución propuesta (presentacion.sh):

    
    
    
    
    
    #!/bin/bash
    
    echo "Mi nombre es Juan Pérez"
    echo "Hoy es $(date +%Y-%m-%d)"
    echo "Estoy trabajando en $(pwd)"
    

    📌 Instrucciones de ejecución:

    Dar permisos:

    
    
    
    
    
    chmod +x presentacion.sh
    

    Ejecutar:

    
    
    
    
    
    ./presentacion.sh
    

    Salida aproximada:

    
    
    
    
    
    Mi nombre es Juan Pérez
    Hoy es 2026-01-10
    Estoy trabajando en /home/juan
    

    Evidentemente, cada alumno pondrá su nombre.


    Ejercicio 3 — Solución

    Enunciado:
    Crear un script que liste los archivos del directorio /etc y guarde el resultado en etc-listado.txt.


    💡 Solución propuesta (listar_etc.sh):

    
    
    
    
    
    #!/bin/bash
    
    ls /etc > etc-listado.txt
    

    📌 Explicación:

    • ls /etc → lista el contenido del directorio /etc
    • > → redirecciona la salida estándar a un archivo

    📌 Instrucciones:

    1. Crear script:
    
    
    
    
    
    nano listar_etc.sh
    
    1. Pegar el contenido, guardar y salir.
    2. Dar permisos:
    
    
    
    
    
    chmod +x listar_etc.sh
    
    1. Ejecutar:
    
    
    
    
    
    ./listar_etc.sh
    
    1. Verificar el resultado:
    
    
    
    
    
    cat etc-listado.txt
    

    Ejemplo de contenido:

    
    
    
    
    

    adduser.conf aliases alternatives apache2 apt bash.bashrc ...

  • 2. Preparación del Entorno y Ejecución de Scripts

    2. Preparación del Entorno y Ejecución de Scripts

    Después de entender qué es Bash y qué es un script, el siguiente paso es aprender a preparar correctamente el entorno de trabajo y ejecutar scripts de forma segura y ordenada.


    1. Crear Scripts Correctamente

    Un script no es más que un archivo de texto plano. Se puede crear con cualquier editor, desde los más simples hasta los más avanzados.

    Editores recomendados:

    • nano (para trabajar en la terminal, muy sencillo)
    • vim (más avanzado, orientado a usuarios expertos)
    • Visual Studio Code (editor gráfico con sintaxis resaltada)
    • gedit o kate (editores gráficos simples)

    Para crear un script:

    
    
    
    
    
    nano mi_script.sh
    

    Se recomienda usar la extensión .sh para identificar que es un script de shell, aunque no es obligatoria.


    2. Añadir el Shebang

    La primera línea del script debe indicar el intérprete que lo ejecutará. Esto se conoce como shebang.

    Ejemplo:

    
    
    
    
    
    #!/bin/bash
    

    Esto garantiza que el script se ejecutará con Bash aunque el sistema use otro shell por defecto.

    Otros ejemplos:

    • #!/bin/sh para un shell más compatible POSIX.
    • #!/usr/bin/env bash para localizar Bash dinámicamente en distintas máquinas.

    3. Permisos de Ejecución

    Un script recién creado no suele tener permisos de ejecución. Para poder ejecutarlo es necesario asignarlos.

    Comando:

    
    
    
    
    
    chmod +x mi_script.sh
    

    Esto indica que el archivo puede ser ejecutado (x) por el usuario.

    Para comprobar los permisos:

    
    
    
    
    
    ls -l mi_script.sh
    

    Ejemplo de salida:

    
    
    
    
    
    -rwxr-xr-x 1 alumno alumno 57 ene 10 18:22 mi_script.sh
    

    4. Ejecutar Scripts

    Hay varias formas de ejecutar un script. Las más comunes son:

    4.1. Ejecutarlo por ruta relativa

    Si estamos en la misma carpeta del script:

    
    
    
    
    
    ./mi_script.sh
    

    El ./ indica “ejecuta este archivo desde el directorio actual”.

    4.2. Ejecutarlo por ruta absoluta

    Ejemplo:

    
    
    
    
    
    /home/alumno/scripts/mi_script.sh
    

    Esto es útil en automatizaciones y servicios del sistema.

    4.3. Ejecutarlo a través del intérprete

    También podemos invocar directamente Bash:

    
    
    
    
    
    bash mi_script.sh
    

    Esto ignora permisos, pero exige que el script sea legible.


    5. Organización del Entorno de Trabajo

    Para no mezclar scripts con otros tipos de archivos, se recomienda crear una carpeta propia:

    
    
    
    
    
    mkdir ~/scripts
    cd ~/scripts
    

    Aquí podemos almacenar scripts y añadir esta carpeta al PATH más adelante para ejecutarlos desde cualquier ubicación.


    6. Variables de Entorno y el PATH

    El PATH es una variable que indica dónde busca el sistema los programas ejecutables.

    Para ver el PATH actual:

    
    
    
    
    
    echo $PATH
    

    Si añadimos nuestros scripts a una carpeta incluida en el PATH, podremos ejecutarlos sin escribir ./ ni rutas completas.

    Más adelante veremos cómo añadir una ruta personalizada al PATH en el archivo .bashrc.


    7. Comentarios y Documentación Interna

    Es recomendable comentar el código para recordar qué hace cada parte. En Bash los comentarios se escriben con #.

    Ejemplo:

    
    
    
    
    
    #!/bin/bash
    # Este script muestra un mensaje por pantalla
    
    echo "Ejecutando mi script..."
    

    Es buena práctica incluir una cabecera con información útil:

    
    
    
    
    
    #!/bin/bash
    # Nombre: backup_home.sh
    # Autor: Nombre del alumno
    # Descripción: Realiza una copia de seguridad del directorio /home
    # Fecha: 10/01/2026
    

    8. Problemas Comunes al Ejecutar Scripts

    Durante este módulo suelen aparecer errores típicos:

    • bash: ./script.sh: Permission denied
      → Falta ejecutar chmod +x script.sh
    • command not found
      → El script no se encuentra o no es ejecutable
    • No such file or directory
      → Error en la ruta o en el nombre del archivo
    • bad interpreter: No such file or directory
      → El shebang apunta a una ruta incorrecta o se usa un archivo generado en Windows con saltos de línea incompatibles

    Este último error aparece mucho cuando se editan scripts en Windows. Se resuelve con:

    
    
    
    
    
    dos2unix script.sh
    

    9. Ejemplo Completo de Script

    Vamos a crear un script que pida un nombre y salude al usuario.

    1. Crear el archivo:
    
    
    
    
    
    nano saludo.sh
    
    1. Contenido:
    
    
    
    
    
    #!/bin/bash
    
    echo "Introduce tu nombre:"
    read nombre
    echo "Hola $nombre, encantado de saludarte."
    
    1. Dar permisos:
    
    
    
    
    
    chmod +x saludo.sh
    
    1. Ejecutarlo:
    
    
    
    
    
    ./saludo.sh
    

    Ejercicios propuestos

    Ejercicio 1:
    Crear un script llamado info.sh que muestre:

    • El usuario actual
    • El directorio donde se encuentra
    • La fecha actual

    Salida orientativa:

    
    
    
    
    
    Usuario: alumno
    Directorio: /home/alumno/scripts
    Fecha: 2026-01-10
    

    Ejercicio 2:
    Crear un script llamado crear_respaldo.sh que:

    • Cree una carpeta respaldo (si no existe)
    • Copie dentro todos los .txt del directorio actual

    Ejercicio 3:
    Mover todos los scripts a ~/scripts/ y probar:

    • Ejecución con ./
    • Ejecución con ruta absoluta

    Ejercicio 4 (opcional):
    Buscar qué es la variable PATH y para qué sirve.

    Soluciones ejercicios

    ✅ Ejercicio 1

    Enunciado:
    Crear un script llamado info.sh que muestre:

    • El usuario actual
    • El directorio donde se encuentra
    • La fecha actual

    💡 Solución propuesta (info.sh)

    
    
    
    
    
    #!/bin/bash
    # Script: info.sh
    # Muestra información básica del sistema y del usuario
    
    echo "Usuario: $USER"
    echo "Directorio actual: $(pwd)"
    echo "Fecha actual: $(date +"%Y-%m-%d %H:%M:%S")"
    

    Notas para clase:

    • $USER viene del entorno.
    • pwd muestra el directorio actual.
    • date formateado con +"%Y-%m-%d %H:%M:%S" muestra fecha y hora legibles.

    ✅ Ejercicio 2

    Enunciado:
    Crear un script llamado crear_respaldo.sh que:

    • Cree una carpeta respaldo (si no existe)
    • Copie dentro todos los .txt del directorio actual

    💡 Solución propuesta básica (crear_respaldo.sh)

    
    
    
    
    
    #!/bin/bash
    # Script: crear_respaldo.sh
    # Crea una carpeta respaldo y copia todos los .txt dentro
    
    # Crear carpeta si no existe
    if [ ! -d "respaldo" ]; then
        echo "Creando carpeta 'respaldo'..."
        mkdir respaldo
    else
        echo "La carpeta 'respaldo' ya existe."
    fi
    
    # Copiar archivos .txt si existen
    if ls *.txt >/dev/null 2>&1; then
        echo "Copiando archivos .txt a 'respaldo'..."
        cp *.txt respaldo/
        echo "Copia completada."
    else
        echo "No se encontraron archivos .txt en el directorio actual."
    fi
    

    Ideas para comentar en clase:

    • [ ! -d "respaldo" ] → comprueba que NO exista el directorio.
    • ls *.txt >/dev/null 2>&1 → truco para comprobar si hay .txt sin mostrar errores.
    • cp *.txt respaldo/ → copia múltiple.

    ✅ Ejercicio 3

    Enunciado:
    Mover todos los scripts a ~/scripts/ y probar:

    • Ejecución con ./
    • Ejecución con ruta absoluta

    Aquí no hay “script solución”, sino comandos que los alumnos deben usar.

    💡 Pasos y comandos

    1. Crear la carpeta scripts en el home (si no existe):
    
    
    
    
    
    mkdir -p ~/scripts
    
    1. Mover los scripts (por ejemplo, info.sh y crear_respaldo.sh) desde el directorio actual:
    
    
    
    
    
    mv info.sh crear_respaldo.sh ~/scripts/
    
    1. Ir a la carpeta:
    
    
    
    
    
    cd ~/scripts
    
    1. Comprobar permisos (por si acaso):
    
    
    
    
    
    chmod +x info.sh crear_respaldo.sh
    
    1. Ejecutar con ruta relativa (estando dentro de ~/scripts):
    
    
    
    
    
    ./info.sh
    ./crear_respaldo.sh
    
    1. Ejecutar con ruta absoluta (desde cualquier sitio):
    
    
    
    
    
    / home /usuario/scripts/info.sh
    

    Sustituyendo usuario por el usuario real, por ejemplo:

    
    
    
    
    
    /home/alumno/scripts/info.sh
    

    ✅ Ejercicio 4

    Enunciado:
    Buscar qué es la variable PATH y para qué sirve.

    Aquí puedes darles una explicación de solución tipo “teoría corregida”.

    💡 Explicación-solución

    La variable PATH:

    • Es una variable de entorno que contiene una lista de rutas separadas por :
    • Indica a la shell en qué directorios buscar ejecutables cuando escribimos un comando sin ruta.

    Por ejemplo, si escribes:

    
    
    
    
    
    ls
    

    La shell busca un archivo ejecutable llamado ls en cada ruta del PATH, en orden.

    Para ver el contenido del PATH:

    
    
    
    
    
    echo $PATH
    

    Ejemplo de salida:

    
    
    
    
    
    /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
    

    Cada ruta separada por : es un directorio donde el sistema busca programas.

    Si añades ~/scripts al PATH, podrías ejecutar info.sh simplemente escribiendo:

    
    
    
    
    
    info.sh
    

    sin ./ ni ruta completa.

  • 3. Variables, Parámetros y Entrada del Usuario

    3. Variables, Parámetros y Entrada del Usuario

    Gracias a las variables y a la entrada de usuario, los scripts dejan de ser estáticos y pueden reaccionar según datos dinámicos.


    1. Variables en Bash

    Una variable es un nombre que almacena un valor. En Bash no se declaran tipos (no hay enteros, strings, booleanos, etc.). Todo se trata como texto y el tipo se deduce según el uso.

    Para crear una variable:

    
    
    
    
    
    variable=valor
    

    No se debe dejar espacio alrededor del =. Para usar la variable:

    
    
    
    
    
    echo $variable
    

    Ejemplo práctico:

    
    
    
    
    
    nombre="Ana"
    echo "Hola $nombre"
    

    Salida:

    
    
    
    
    
    Hola Ana
    

    Variables útiles del sistema

    Existen variables ya definidas por el entorno, por ejemplo:

    • $USER → usuario actual
    • $HOME → directorio personal
    • $SHELL → shell en uso
    • $PWD → directorio actual
    • $RANDOM → número aleatorio

    Ejemplo:

    
    
    
    
    
    echo "Tu usuario es $USER y estás en $PWD"
    

    2. Parámetros Posicionales

    Son valores que se pasan al script al ejecutarlo desde la terminal. Permiten que un mismo script funcione para diferentes entradas sin modificar su contenido.

    Ejemplo de ejecución:

    
    
    
    
    
    ./mi_script.sh valor1 valor2 valor3
    

    Dentro del script:

    • $1 será valor1
    • $2 será valor2
    • $3 será valor3

    $# indica cuántos parámetros se han recibido.

    $@ representa todos los parámetros juntos.

    Ejemplo práctico (parametros.sh):

    
    
    
    
    
    #!/bin/bash
    
    echo "Primer parámetro: $1"
    echo "Segundo parámetro: $2"
    echo "Total de parámetros: $#"
    

    Ejecutando:

    
    
    
    
    
    ./parametros.sh gato perro
    

    Salida:

    
    
    
    
    
    Primer parámetro: gato
    Segundo parámetro: perro
    Total de parámetros: 2
    

    3. Entrada Interactiva con read

    El comando read permite que el script espere que el usuario escriba algo por teclado.

    Ejemplo básico:

    
    
    
    
    
    #!/bin/bash
    
    echo "Introduce tu nombre:"
    read nombre
    echo "Encantado de saludarte, $nombre"
    

    Es posible usar read con opciones:

    • -p para mostrar un mensaje sin usar echo
    • -s para ocultar lo que se escribe (útil para contraseñas)
    • -n para captar un número concreto de caracteres

    Ejemplos:

    
    
    
    
    
    read -p "Introduce tu usuario: " usuario
    read -s -p "Introduce tu contraseña: " pass
    echo
    echo "Usuario: $usuario"
    

    4. Aritmética en Bash

    Aunque todo es texto, Bash permite operaciones aritméticas básicas:

    Sintaxis:

    
    
    
    
    
    resultado=$(( expresion ))
    

    Ejemplo:

    
    
    
    
    
    a=7
    b=3
    c=$((a + b))
    echo "Resultado: $c"
    

    Salida esperada:

    
    
    
    
    
    Resultado: 10
    

    Operadores soportados:

    • + suma
    • - resta
    • * multiplicación
    • / división entera
    • % módulo

    5. Combinando Variables con Texto

    En Bash no hace falta concatenar como en otros lenguajes. Se puede insertar directamente la variable en cadenas.

    Ejemplo:

    
    
    
    
    
    nombre="Lucía"
    echo "Bienvenida $nombre al sistema"
    

    Si una variable está pegada a texto, conviene usar llaves { }:

    
    
    
    
    
    version="1.0"
    echo "Versión: v${version}"
    

    6. Ejemplos Completos

    Ejemplo 1: Script que saluda usando read

    
    
    
    
    
    #!/bin/bash
    
    read -p "Introduce tu nombre: " nombre
    echo "Hola $nombre, bienvenido."
    

    Ejemplo 2: Sumar dos números recibidos como parámetros

    
    
    
    
    
    #!/bin/bash
    
    a=$1
    b=$2
    echo "La suma es: $((a + b))"
    

    Ejecutar:

    
    
    
    
    
    ./sumar.sh 4 8
    

    Salida:

    
    
    
    
    
    La suma es: 12
    

    Ejemplo 3: Generar un archivo con información

    
    
    
    
    
    #!/bin/bash
    
    usuario=$USER
    fecha=$(date +%Y-%m-%d)
    pwd=$(pwd)
    
    echo "Usuario: $usuario" > info.txt
    echo "Fecha: $fecha" >> info.txt
    echo "Directorio: $pwd" >> info.txt
    

    Ejercicios propuestos

    Ejercicio 1:
    Crear un script llamado edad.sh que pida el nombre del usuario y su edad, luego muestre un mensaje tipo:

    
    
    
    
    
    Hola Ana, tienes 23 años.
    

    Ejercicio 2:
    Crear un script suma.sh que reciba dos números como parámetros y muestre:

    
    
    
    
    
    La suma de X + Y es Z
    

    Ejercicio 3:
    Crear un script logear.sh que pida un usuario y contraseña con read, y que oculte la contraseña al escribir.

    Ejercicio 4:
    Crear un script contador.sh que muestre cuántos parámetros se han pasado al script y liste cada uno en una línea.


    Soluciones

    ✅ Ejercicio 1 – edad.sh

    Enunciado:
    Crear un script que pida el nombre del usuario y su edad, luego muestre algo como:

    Hola Ana, tienes 23 años.

    Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: edad.sh
    # Pide nombre y edad y muestra un mensaje
    
    read -p "Introduce tu nombre: " nombre
    read -p "Introduce tu edad: " edad
    
    echo "Hola $nombre, tienes $edad años."
    

    ✅ Ejercicio 2 – suma.sh

    Enunciado:
    Crear un script suma.sh que reciba dos números como parámetros y muestre:

    La suma de X + Y es Z

    Solución básica (asumiendo que siempre pasan 2 números):

    
    
    
    
    
    #!/bin/bash
    # Script: suma.sh
    # Suma dos números pasados como parámetros
    
    a=$1
    b=$2
    
    resultado=$((a + b))
    
    echo "La suma de $a + $b es $resultado"
    

    Versión un poco más robusta (comprobando parámetros):

    
    
    
    
    
    #!/bin/bash
    # Script: suma.sh
    # Suma dos números pasados como parámetros con validación básica
    
    if [ $# -ne 2 ]; then
        echo "Uso: $0 num1 num2"
        exit 1
    fi
    
    a=$1
    b=$2
    
    resultado=$((a + b))
    
    echo "La suma de $a + $b es $resultado"
    

    ✅ Ejercicio 3 – logear.sh

    Enunciado:
    Crear un script logear.sh que pida usuario y contraseña con read, ocultando la contraseña al escribir.

    Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: logear.sh
    # Pide usuario y contraseña (sin mostrar la contraseña)
    
    read -p "Usuario: " usuario
    read -s -p "Contraseña: " password
    echo
    echo "Has introducido el usuario: $usuario"
    echo "La contraseña se ha recibido (no se muestra por seguridad)."
    

    Si quieres rizar el rizo en clase, puedes decir que en un caso real no se mostraría nada de la contraseña ni se imprimiría.


    ✅ Ejercicio 4 – contador.sh

    Enunciado:
    Crear un script contador.sh que:

    • Muestre cuántos parámetros se han pasado.
    • Liste cada uno en una línea.

    Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: contador.sh
    # Muestra cuántos parámetros se han pasado y los lista
    
    echo "Se han pasado $# parámetros."
    
    # Si no hay parámetros, avisamos
    if [ $# -eq 0 ]; then
        echo "No se ha pasado ningún parámetro."
        exit 0
    fi
    
    echo "Listado de parámetros:"
    contador=1
    for param in "$@"; do
        echo "Parámetro $contador: $param"
        contador=$((contador + 1))
    done
    

    Ejemplo de ejecución:

    
    
    
    
    
    ./contador.sh uno dos tres
    

    Salida:

    
    
    
    
    
    Se han pasado 3 parámetros.
    Listado de parámetros:
    Parámetro 1: uno
    Parámetro 2: dos
    Parámetro 3: tres
    

  • 4. Operadores, Condicionales y Comparaciones

    Hasta ahora tus scripts ejecutaban instrucciones una detrás de otra. Eso está bien, pero es limitado. Para tomar decisiones en un script necesitas condiciones: comprobar valores, comparar texto o números, verificar si existen archivos, etc.

    Este módulo introduce las herramientas para que un script pueda responder dinámicamente a distintas situaciones.


    1. El bloque if en Bash

    La estructura básica es:

    
    
    
    
    
    if [ condición ]; then
        comandos
    fi
    

    Ejemplo:

    
    
    
    
    
    numero=10
    
    if [ $numero -gt 5 ]; then
        echo "El número es mayor que 5"
    fi
    

    El then va en la misma línea que if, o en la siguiente separado por ;.


    2. if / elif / else

    Para varias condiciones se usa elif (“else if”):

    
    
    
    
    
    if [ condición1 ]; then
        comandos
    elif [ condición2 ]; then
        comandos
    else
        comandos por defecto
    fi
    

    Ejemplo:

    
    
    
    
    
    edad=15
    
    if [ $edad -ge 18 ]; then
        echo "Mayor de edad"
    else
        echo "Menor de edad"
    fi
    

    3. Tipos de comparaciones

    Hay dos grandes tipos: numéricas y de cadenas.

    3.1 Comparaciones numéricas

    Se usan operadores de una sola palabra:

    • -eq → igual
    • -ne → distinto
    • -gt → mayor que (“greater than”)
    • -ge → mayor o igual
    • -lt → menor que
    • -le → menor o igual

    Ejemplo:

    
    
    
    
    
    if [ $x -lt 100 ]; then
        echo "x es menor que 100"
    fi
    

    3.2 Comparaciones de cadenas

    Se usan:

    • = → igual
    • != → distinto
    • -z → cadena vacía
    • -n → cadena NO vacía

    Ejemplos:

    
    
    
    
    
    if [ "$nombre" = "Ana" ]; then
        echo "Hola Ana"
    fi
    
    
    
    
    
    
    if [ -z "$variable" ]; then
        echo "La variable está vacía"
    fi
    

    Importante entrecomillar variables para evitar errores cuando están vacías.


    4. Comparación avanzada con [[ ]]

    Bash también admite [[ ]], que permite hacer comparaciones más modernas y usar patrones (==, !=, comodines).

    Ejemplo:

    
    
    
    
    
    if [[ $animal == "gato" ]]; then
        echo "Es un gato"
    fi
    

    Permite patrones:

    
    
    
    
    
    if [[ $nombre == A* ]]; then
        echo "El nombre empieza por A"
    fi
    

    5. Operadores lógicos (&&, ||)

    Se pueden combinar condiciones:

    • && → Y lógico
    • || → O lógico

    Ejemplo:

    
    
    
    
    
    if [ $edad -ge 18 ] && [ $edad -lt 65 ]; then
        echo "Adulto en edad laboral"
    fi
    

    Otro ejemplo con ||:

    
    
    
    
    
    if [ "$respuesta" = "S" ] || [ "$respuesta" = "s" ]; then
        echo "Respuesta afirmativa"
    fi
    

    6. Condiciones sobre archivos

    En administración de sistemas esto se usa TODO el tiempo.

    Operadores útiles:

    • -f archivo → existe y es archivo regular
    • -d ruta → existe y es directorio
    • -r archivo → se puede leer
    • -w archivo → se puede escribir
    • -x archivo → se puede ejecutar

    Ejemplos:

    
    
    
    
    
    if [ -d /etc ]; then
        echo "/etc existe"
    fi
    
    
    
    
    
    
    if [ -f datos.txt ]; then
        echo "El archivo datos.txt existe"
    fi
    

    7. El comando test

    [ ] es un alias de test.

    Las siguientes líneas son equivalentes:

    
    
    
    
    
    if [ $x -gt 10 ]
    

    y

    
    
    
    
    
    if test $x -gt 10
    

    No cambia nada en lógica, pero conviene conocerlo porque se ve mucho en scripts antiguos.


    8. El case: otra forma de decidir

    Cuando hay muchas opciones, case evita varios elif seguidos.

    Sintaxis:

    
    
    
    
    
    case $variable in
        opción1)
            comandos ;;
        opción2)
            comandos ;;
        *)
            comandos por defecto ;;
    esac
    

    Ejemplo:

    
    
    
    
    
    read -p "Introduce una letra: " letra
    
    case $letra in
        a|A) echo "Has pulsado A" ;;
        b|B) echo "Has pulsado B" ;;
        *) echo "Opción no reconocida" ;;
    esac
    

    Muy útil para menús interactivos.


    9. Ejemplos

    Ejemplo 1: Verificar si un archivo existe

    
    
    
    
    
    #!/bin/bash
    
    if [ -f "$1" ]; then
        echo "El archivo $1 existe."
    else
        echo "El archivo $1 no existe."
    fi
    

    Ejemplo 2: Verificar si un usuario es mayor de edad

    
    
    
    
    
    #!/bin/bash
    
    read -p "Introduce tu edad: " edad
    
    if [ $edad -ge 18 ]; then
        echo "Eres mayor de edad."
    else
        echo "Eres menor de edad."
    fi
    

    Ejemplo 3: Menú con case

    
    
    
    
    
    #!/bin/bash
    
    echo "1) Mostrar fecha"
    echo "2) Mostrar usuario"
    echo "3) Salir"
    
    read -p "Elige una opción: " opcion
    
    case $opcion in
        1) date ;;
        2) echo "Usuario: $USER" ;;
        3) echo "Adiós" ;;
        *) echo "Opción no válida" ;;
    esac
    

    Ejercicios propuestos

    Ejercicio 1:
    Crear un script mayor.sh que pida un número y diga si es mayor, menor o igual que 100.

    Ejercicio 2:
    Crear un script existe.sh que reciba un nombre de archivo como parámetro y diga si existe y si es archivo o directorio.

    Ejercicio 3:
    Crear un script menu.sh que muestre tres opciones con case:

    • Mostrar nombre de usuario
    • Mostrar fecha
    • Salir

    Ejercicio 4:
    Crear un script login.sh que pida usuario y contraseña y verifique:

    • Si el usuario es «admin»
    • Si la contraseña es «secreto»

    Mostrará “Acceso permitido” o “Acceso denegado”.

    Soluciones

    Ejercicio 1 — mayor.sh

    Enunciado:
    Pedir un número y decir si es mayor, menor o igual que 100.

    Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: mayor.sh
    # Compara un número con 100
    
    read -p "Introduce un número: " num
    
    if [ "$num" -gt 100 ]; then
        echo "$num es mayor que 100"
    elif [ "$num" -lt 100 ]; then
        echo "$num es menor que 100"
    else
        echo "$num es igual a 100"
    fi
    

    Ejemplo de uso:

    Entrada: 120
    Salida: 120 es mayor que 100


    Ejercicio 2 — existe.sh

    Enunciado:
    Recibir un nombre de archivo/directorio como parámetro y comprobar:

    • Si existe
    • Si es archivo o directorio

    Solución con validación básica:

    
    
    
    
    
    #!/bin/bash
    # Script: existe.sh
    # Comprueba si un archivo/directorio existe
    
    if [ $# -ne 1 ]; then
        echo "Uso: $0 nombre_archivo"
        exit 1
    fi
    
    ruta="$1"
    
    if [ -e "$ruta" ]; then
        if [ -f "$ruta" ]; then
            echo "$ruta existe y es un archivo"
        elif [ -d "$ruta" ]; then
            echo "$ruta existe y es un directorio"
        else
            echo "$ruta existe, pero no es archivo ni directorio común"
        fi
    else
        echo "$ruta no existe"
    fi
    

    Ejemplo de uso:

    
    
    
    
    
    ./existe.sh /etc
    

    Salida:

    
    
    
    
    
    /etc existe y es un directorio
    

    Ejercicio 3 — menu.sh

    Enunciado:
    Crear un menú con case que muestre tres opciones:

    1. Mostrar nombre de usuario
    2. Mostrar fecha
    3. Salir

    Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: menu.sh
    # Menú básico con case
    
    echo "Menú:"
    echo "1) Mostrar nombre de usuario"
    echo "2) Mostrar fecha"
    echo "3) Salir"
    
    read -p "Elige una opción: " opcion
    
    case "$opcion" in
        1)
            echo "Usuario: $USER"
            ;;
        2)
            echo "Fecha actual: $(date +"%Y-%m-%d %H:%M:%S")"
            ;;
        3)
            echo "Saliendo..."
            ;;
        *)
            echo "Opción no válida"
            ;;
    esac
    

    Ejemplo:

    Entrada: 2
    Salida (aprox):

    
    
    
    
    
    Fecha actual: 2026-01-11 18:42:00
    

    Ejercicio 4 — login.sh

    Enunciado:
    Pedir usuario y contraseña y verificar:

    • usuario == admin
    • contraseña == secreto

    Si coincide: Acceso permitido
    Si no: Acceso denegado

    Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: login.sh
    # Verificación simple de usuario/contraseña
    
    read -p "Usuario: " usuario
    read -s -p "Contraseña: " password
    echo
    
    if [ "$usuario" = "admin" ] && [ "$password" = "secreto" ]; then
        echo "Acceso permitido"
    else
        echo "Acceso denegado"
    fi
    

    Ejemplo:

    Entrada:

    
    
    
    
    
    Usuario: admin
    Contraseña: secreto
    

    Salida:

    
    
    
    
    
    Acceso permitido
  • 5. Bucles y Estructuras de Repetición

    Los bucles permiten ejecutar un conjunto de instrucciones varias veces. Son esenciales en automatización, análisis de archivos, procesado de datos, monitoreo y en general cualquier script útil.

    En Bash disponemos de varias estructuras de repetición: for, while, until y control de bucles mediante break y continue.


    1. Bucle for

    Ideal para iterar sobre listas, rangos o elementos concretos.

    1.1. Iterar sobre una lista

    Sintaxis:

    
    
    
    
    
    for var in elemento1 elemento2 elemento3; do
        comandos
    done
    

    Ejemplo:

    
    
    
    
    
    for animal in perro gato loro; do
        echo "Animal: $animal"
    done
    

    Salida:

    
    
    
    
    
    Animal: perro
    Animal: gato
    Animal: loro
    

    1.2. Iterar sobre un rango

    
    
    
    
    
    for i in {1..5}; do
        echo "Número: $i"
    done
    

    Salida:

    
    
    
    
    
    Número: 1
    Número: 2
    Número: 3
    Número: 4
    Número: 5
    

    1.3. Iterar sobre archivos

    
    
    
    
    
    for archivo in *.txt; do
        echo "Procesando $archivo"
    done
    

    Muy útil para automatizar tareas sobre lotes de archivos.


    2. Bucle while

    Ejecuta instrucciones mientras se cumpla una condición.

    Sintaxis:

    
    
    
    
    
    while [ condición ]; do
        comandos
    done
    

    Ejemplo:

    
    
    
    
    
    contador=1
    while [ $contador -le 5 ]; do
        echo "Contador: $contador"
        contador=$((contador + 1))
    done
    

    2.1. Leer archivo línea a línea

    Excelente para procesar logs o datos estructurados.

    
    
    
    
    
    while read linea; do
        echo "$linea"
    done < archivo.txt
    

    3. Bucle until

    Es lo inverso a while: ejecuta hasta que se cumpla una condición.

    Sintaxis:

    
    
    
    
    
    until [ condición ]; do
        comandos
    done
    

    Ejemplo:

    
    
    
    
    
    contador=1
    until [ $contador -gt 5 ]; do
        echo "Contador: $contador"
        contador=$((contador + 1))
    done
    

    Hace lo mismo que el ejemplo de while, pero con lógica inversa.


    4. Control del Flujo: break y continue

    break

    Termina el bucle antes de tiempo.

    Ejemplo:

    
    
    
    
    
    for i in {1..10}; do
        if [ $i -eq 5 ]; then
            break
        fi
        echo "i = $i"
    done
    

    Salida:

    
    
    
    
    
    i = 1
    i = 2
    i = 3
    i = 4
    

    continue

    Salta a la siguiente iteración sin terminar el bucle.

    Ejemplo:

    
    
    
    
    
    for i in {1..5}; do
        if [ $i -eq 3 ]; then
            continue
        fi
        echo "i = $i"
    done
    

    Salida:

    
    
    
    
    
    i = 1
    i = 2
    i = 4
    i = 5
    

    5. Bucles Anidados

    Se puede meter un bucle dentro de otro.

    Ejemplo:

    
    
    
    
    
    for i in {1..3}; do
        for j in {1..2}; do
            echo "i=$i, j=$j"
        done
    done
    

    6. Ejemplos Aplicados

    Ejemplo 1: Contador simple

    
    
    
    
    
    #!/bin/bash
    
    for i in {1..10}; do
        echo "Número: $i"
    done
    

    Ejemplo 2: Procesar todos los .log

    
    
    
    
    
    #!/bin/bash
    
    for log in *.log; do
        echo "Analizando $log..."
    done
    

    Ejemplo 3: Ping a una subred

    
    
    
    
    
    #!/bin/bash
    
    for i in {1..254}; do
        ping -c 1 192.168.1.$i >/dev/null 2>&1
        if [ $? -eq 0 ]; then
            echo "192.168.1.$i está activo"
        fi
    done
    

    Ejemplo 4: Leer archivo línea a línea

    
    
    
    
    
    #!/bin/bash
    
    while read linea; do
        echo "Línea: $linea"
    done < usuarios.txt
    

    Ejercicios propuestos

    Ejercicio 1:
    Crear un script cuenta.sh que muestre los números del 1 al 20 usando for.

    Ejercicio 2:
    Crear un script files.sh que liste todos los archivos del directorio actual y muestre cuántos hay al final.

    Ejercicio 3:
    Crear un script ping.sh que pida una IP base (por ejemplo 192.168.1) y haga ping del .1 al .10, mostrando solo los que respondan.

    Ejercicio 4:
    Crear un script leer.sh que lea un archivo de texto pasado como parámetro y muestre cada línea precedida del número de línea:

    Ejemplo:

    
    
    
    
    
    1: línea uno
    2: línea dos
    3: línea tres
    

    Soluciones

    ✅ Ejercicio 1 — cuenta.sh

    Enunciado:
    Crear un script cuenta.sh que muestre los números del 1 al 20 usando for.

    💡 Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: cuenta.sh
    # Muestra los números del 1 al 20
    
    for i in {1..20}; do
        echo "$i"
    done
    

    Salida esperada:

    
    
    
    
    
    1
    2
    3
    ...
    20
    

    ✅ Ejercicio 2 — files.sh

    Enunciado:
    Crear un script files.sh que liste todos los archivos del directorio actual y muestre cuántos hay al final.

    💡 Solución sencilla (con ls y wc -l):

    
    
    
    
    
    #!/bin/bash
    # Script: files.sh
    # Lista los archivos del directorio actual y muestra cuántos hay
    
    echo "Archivos en el directorio actual:"
    ls
    
    echo
    total=$(ls | wc -1)
    echo "Total de entradas: $total"
    

    Nota: ls lista tanto archivos como directorios. Para un curso inicial está bien.

    💡 Versión algo más “didáctica” con for y contador:

    
    
    
    
    
    #!/bin/bash
    # Script: files.sh
    # Recorre las entradas del directorio actual y las cuenta
    
    contador=0
    
    echo "Entradas en el directorio actual:"
    for item in *; do
        echo "$item"
        contador=$((contador + 1))
    done
    
    echo
    echo "Total de entradas: $contador"
    

    ✅ Ejercicio 3 — ping.sh

    Enunciado:
    Crear un script ping.sh que pida una IP base (por ejemplo 192.168.1) y haga ping del .1 al .10, mostrando solo las IP que respondan.

    💡 Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: ping.sh
    # Hace ping a una serie de IPs de la misma red (del .1 al .10)
    
    read -p "Introduce la IP base (ej: 192.168.1): " base
    
    for i in {1..10}; do
        ip="$base.$i"
        ping -c 1 -W 1 "$ip" >/dev/null 2>&1
        if [ $? -eq 0 ]; then
            echo "$ip está ACTIVA"
        else
            echo "$ip no responde"
        fi
    done
    

    Si quieres que solo muestre las activas, quitas el else:

    
    
    
    
    
    #!/bin/bash
    # Solo muestra las IP que responden
    
    read -p "Introduce la IP base (ej: 192.168.1): " base
    
    for i in {1..10}; do
        ip="$base.$i"
        ping -c 1 -W 1 "$ip" >/dev/null 2>&1
        if [ $? -eq 0 ]; then
            echo "$ip está ACTIVA"
        fi
    done
    

    ✅ Ejercicio 4 — leer.sh

    Enunciado:
    Crear un script leer.sh que lea un archivo de texto pasado como parámetro y muestre cada línea precedida del número de línea:

    Ejemplo:

    
    
    
    
    
    1: línea uno
    2: línea dos
    3: línea tres
    

    💡 Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: leer.sh
    # Muestra un archivo línea a línea con número de línea
    
    if [ $# -ne 1 ]; then
        echo "Uso: $0 archivo"
        exit 1
    fi
    
    archivo="$1"
    
    if [ ! -f "$archivo" ]; then
        echo "El archivo '$archivo' no existe o no es un archivo regular."
        exit 1
    fi
    
    num_linea=1
    while read linea; do
        echo "$num_linea: $linea"
        num_linea=$((num_linea + 1))
    done < "$archivo"
    

    Ejemplo de uso:

    
    
    
    
    
    ./leer.sh notas.txt
    

    Salida:

    
    
    
    
    
    1: primera línea del archivo
    2: segunda línea del archivo
    3: tercera línea...
    

  • 6. Arrays y Gestión de Colecciones

    6. Arrays y Gestión de Colecciones

    En Bash, un array es una variable que puede almacenar múltiples valores. Son muy útiles cuando queremos guardar listas de elementos (archivos, usuarios, números, etc.) y procesarlos más tarde con bucles.

    Este módulo te permitirá trabajar con colecciones simples y asociativas, acceder a valores por índice, añadir elementos y recorrer los arrays.


    1. Arrays Indexados

    Los arrays indexados usan números enteros como índices, empezando por 0.

    1.1 Crear un array

    Varias formas:

    
    
    
    
    
    nombres=("Ana" "Luis" "Carlos")
    

    o

    
    
    
    
    
    nombres[0]="Ana"
    nombres[1]="Luis"
    nombres[2]="Carlos"
    

    1.2 Acceder a elementos

    Acceso mediante índices:

    
    
    
    
    
    echo ${nombres[0]}
    

    Salida:

    
    
    
    
    
    Ana
    

    1.3 Mostrar todos los elementos

    
    
    
    
    
    echo ${nombres[@]}
    

    o

    
    
    
    
    
    echo ${nombres[*]}
    

    1.4 Contar elementos

    
    
    
    
    
    echo ${#nombres[@]}
    

    Ejemplo:

    
    
    
    
    
    nombres=("Ana" "Luis" "Carlos")
    echo ${#nombres[@]}    # muestra 3
    

    Cuando trabajas con arrays:

    SímboloEjemploSignificado
    @${array[@]}Todos los elementos del array por separado.
    *${array[*]}Todos los elementos como una única cadena.
    #${#array[@]}Número de elementos del array.
    []${array[2]}Acceder al índice 2 del array.


    ${array[@]} y ${array[*]} parecen iguales, pero no lo son cuando hay espacios:

    • "${array[@]}" → cada elemento es una palabra independiente
    • "${array[*]}" → todo se convierte en una única cadena

    Esto afecta a bucles, argumentos, etc.

    1.5 Añadir elementos

    
    
    
    
    
    nombres+=("Sofía")
    

    o por índice:

    
    
    
    
    
    nombres[3]="Sofía"
    

    1.6 Eliminar elementos

    Se puede borrar un índice concreto:

    
    
    
    
    
    unset nombres[1]
    

    Esto no reorganiza los índices, simplemente deja un “hueco”.


    2. Recorrer Arrays

    La manera más común es con for:

    
    
    
    
    
    nombres=("Ana" "Luis" "Carlos")
    
    for nombre in "${nombres[@]}"; do
        echo "Nombre: $nombre"
    done
    

    Salida:

    
    
    
    
    
    Nombre: Ana
    Nombre: Luis
    Nombre: Carlos
    

    3. Arrays Asociativos

    Los arrays asociativos permiten guardar pares clave → valor, similar a diccionarios o mapas.

    3.1 Declaración

    Hay que declararlos antes:

    
    
    
    
    
    declare -A capitales
    

    3.2 Asignación

    
    
    
    
    
    capitales[España]="Madrid"
    capitales[Francia]="París"
    capitales[Italia]="Roma"
    

    3.3 Acceso por clave

    
    
    
    
    
    echo ${capitales[Francia]}
    

    Salida:

    
    
    
    
    
    París
    

    3.4 Listar claves

    
    
    
    
    
    echo ${!capitales[@]}
    

    3.5 Listar valores

    
    
    
    
    
    echo ${capitales[@]}
    

    4. Casos de uso comunes

    4.1 Guardar usuarios del sistema

    
    
    
    
    
    usuarios=($(cut -d: -f1 /etc/passwd))
    

    4.2 Guardar archivos por extensión

    
    
    
    
    
    imagenes=(*.jpg *.png *.gif)
    

    4.3 Guardar resultados de un comando

    
    
    
    
    
    procesos=($(ps -e | awk '{print $1}'))
    

    5. Simbologías en bash

    En Bash aparecen unos símbolos “místicos” que parecen sacados de la iconografía nórdica (@, *, #, etc.) y que tienen significados distintos según el contexto.


    a) En arrays Bash

    Cuando trabajas con arrays:

    SímboloEjemploSignificado
    @${array[@]}Todos los elementos del array por separado.
    *${array[*]}Todos los elementos como una única cadena.
    #${#array[@]}Número de elementos del array.
    []${array[2]}Acceder al índice 2 del array.

    Matiz interesante:
    ${array[@]} y ${array[*]} parecen iguales, pero no lo son cuando hay espacios:

    • "${array[@]}" → cada elemento es una palabra independiente
    • "${array[*]}" → todo se convierte en una única cadena

    Esto afecta a bucles, argumentos, etc.


    b) En parámetros posicionales ($1, $2, etc.)

    Cuando el script recibe argumentos:

    SímboloEjemploSignificado
    @"$@"Todos los parámetros, cada uno como una palabra independiente.
    *"$*"Todos los parámetros como una sola palabra.
    #$#Número total de parámetros recibidos.
    0$0Nombre del script.
    1,2,3…$1, $2Parám. posicionales: primero, segundo, etc.

    Ejemplo visual:

    Si ejecutas:

    
    
    
    
    
    ./script.sh uno "dos tres" cuatro
    
    • "$@"uno dos tres cuatro (3 palabras)
    • "$*"uno dos tres cuatro (1 palabra grande)

    c) En globbing (patrones de archivos)

    Cuando expandes patrones en el shell:

    PatrónEjemploSignificado
    **.txtCualquier cadena (0 o más caracteres).
    ?t?.txtUn solo carácter desconocido.
    []t[aeiou].txtClase de caracteres posibles.
    [^ ]t[^a].txtClase negada (cualquiera menos “a”).
    {}{jpg,png}Expansión de listas.

    Ejemplos rápidos:

    • *.txt coincide con hola.txt, notas.txt, etc.
    • ???.txt coincide con uno.txt pero no con hola.txt.
    • f[oa]r.txt coincide con for.txt y far.txt.

    d) En cadenas (longitud y sustitución)

    El símbolo # también sirve para medir longitudes:

    SímboloEjemploSignificado
    #${#var}Longitud de la variable “var”.
    %${var%pat}Elimina el patrón más corto por la derecha.
    %%${var%%pat}Elimina el patrón más largo por la derecha.
    #${var#pat}Elimina el patrón más corto por la izquierda.
    ##${var##pat}Elimina el patrón más largo por la izquierda.

    Ejemplo rápido:

    
    
    
    
    
    var="archivo.tar.gz"
    echo ${var%.*}   # archivo.tar
    echo ${var%%.*}  # archivo
    

    Resumen

    Contexto@*#
    ArraysElementos separadosElementos juntosNúmero de elementos
    Parámetros del scriptArgs separadosArgs juntosNúmero de args
    GlobbingCualquier cadena
    CadenasLongitud

    6. Ejemplos Aplicados

    Ejemplo 1: Lista de frutas

    
    
    
    
    
    #!/bin/bash
    
    frutas=("Manzana" "Pera" "Uva")
    for fruta in "${frutas[@]}"; do
        echo "Fruta: $fruta"
    done
    

    Ejemplo 2: Contar elementos

    
    
    
    
    
    #!/bin/bash
    
    colores=("Rojo" "Azul" "Verde" "Amarillo")
    echo "Hay ${#colores[@]} colores en la lista."
    

    Ejemplo 3: Asociar países con capitales

    
    
    
    
    
    #!/bin/bash
    
    declare -A capitales
    capitales[España]="Madrid"
    capitales[Alemania]="Berlín"
    
    for pais in "${!capitales[@]}"; do
        echo "La capital de $pais es ${capitales[$pais]}"
    done
    

    Ejercicios propuestos

    Ejercicio 1:
    Crear un script frutas.sh con un array de frutas y recorrerlo con un for mostrando los elementos.

    Ejercicio 2:
    Crear un script contar.sh que almacene números del 10 al 50 en un array y muestre cuántos elementos contiene.

    Ejercicio 3:
    Crear un script capitales.sh con un array asociativo de países → capitales y luego imprimir:

    
    
    
    
    
    La capital de X es Y
    

    para cada país.

    Ejercicio 4:
    Crear un script archivos.sh que guarde en un array todos los archivos .txt del directorio actual y los liste.


    Soluciones

    ✅ Ejercicio 1 — frutas.sh

    Enunciado:
    Crear un script frutas.sh con un array de frutas y recorrerlo con un for mostrando los elementos.

    💡 Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: frutas.sh
    # Muestra una lista de frutas usando un array
    
    frutas=("Manzana" "Pera" "Naranja" "Plátano" "Kiwi")
    
    echo "Listado de frutas:"
    for fruta in "${frutas[@]}"; do
        echo " - $fruta"
    done
    

    Salida esperada:

    
    
    
    
    
    Listado de frutas:
     - Manzana
     - Pera
     - Naranja
     - Plátano
     - Kiwi
    

    ✅ Ejercicio 2 — contar.sh

    Enunciado:
    Crear un script contar.sh que almacene números del 10 al 50 en un array y muestre cuántos elementos contiene.

    Puedes interpretarlo de varias formas. Te dejo una solución clara y didáctica.

    💡 Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: contar.sh
    # Guarda números del 10 al 50 en un array y muestra cuántos hay
    
    numeros=()
    
    for ((i=10; i<=50; i++)); do
        numeros+=("$i")
    done
    
    echo "Contenido del array:"
    echo "${numeros[@]}"
    
    echo
    echo "El array contiene ${#numeros[@]} elementos."
    

    Salida (resumen):

    
    
    
    
    
    Contenido del array:
    10 11 12 ... 50
    
    El array contiene 41 elementos.
    

    ✅ Ejercicio 3 — capitales.sh

    Enunciado:
    Crear un script capitales.sh con un array asociativo de países → capitales y luego imprimir:

    La capital de X es Y

    para cada país.

    💡 Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: capitales.sh
    # Usa un array asociativo para países y capitales
    
    declare -A capitales
    
    capitales[España]="Madrid"
    capitales[Francia]="París"
    capitales[Alemania]="Berlín"
    capitales[Italia]="Roma"
    capitales[Portugal]="Lisboa"
    
    for pais in "${!capitales[@]}"; do
        echo "La capital de $pais es ${capitales[$pais]}"
    done
    

    Salida posible (el orden puede variar, porque los asociativos no garantizan orden):

    
    
    
    
    
    La capital de España es Madrid
    La capital de Francia es París
    La capital de Alemania es Berlín
    La capital de Italia es Roma
    La capital de Portugal es Lisboa
    

    ✅ Ejercicio 4 — archivos.sh

    Enunciado:
    Crear un script archivos.sh que guarde en un array todos los archivos .txt del directorio actual y los liste.

    💡 Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: archivos.sh
    # Guarda en un array los .txt del directorio actual y los muestra
    
    txt_files=(*.txt)
    
    # Comprobamos si hay alguno
    if [ "${#txt_files[@]}" -eq 1 ] && [ "${txt_files[0]}" = "*.txt" ]; then
        echo "No se han encontrado archivos .txt en el directorio actual."
        exit 0
    fi
    
    echo "Archivos .txt encontrados:"
    for fichero in "${txt_files[@]}"; do
        echo " - $fichero"
    done
    
    echo
    echo "Total de archivos .txt: ${#txt_files[@]}"
    

    Notas:

    • El truco de comprobar si el único elemento es "*.txt" evita el caso en que no haya .txt y el patrón no se expanda.
    • Esto da pie a hablar de globbing y de nullglob en niveles más avanzados.

  • 7. Funciones y Modularización del Código

    Los scripts que has hecho hasta ahora funcionan bien, pero tienen un problema: si el código crece, se convierte en algo difícil de mantener, leer y modificar. Las funciones solucionan esto al permitir reutilizar código y dividirlo en partes más pequeñas.

    Este módulo te enseñará a definir funciones, pasar argumentos, devolver valores y modularizar scripts más complejos.


    1. ¿Qué es una función en Bash?

    Una función es un bloque de código con nombre propio que puedes ejecutar cuando quieras, tantas veces como quieras.

    En pseudolenguaje:

    
    
    
    
    
    definir función → hacer algo
    llamar función → ejecuta ese algo
    

    2. Sintaxis para definir funciones

    Bash acepta dos sintaxis equivalentes:

    Forma 1:

    
    
    
    
    
    nombre_funcion() {
        comandos
    }
    

    Forma 2:

    
    
    
    
    
    function nombre_funcion {
        comandos
    }
    

    Ambas son válidas. Lo más usado es la primera por ser más limpia.


    3. Llamar a una función

    Una vez definida, basta con usar su nombre:

    
    
    
    
    
    mi_funcion
    

    Ejemplo:

    
    
    
    
    
    saludar() {
        echo "Hola desde la función"
    }
    
    saludar
    

    Salida:

    
    
    
    
    
    Hola desde la función
    

    4. Funciones con parámetros

    Las funciones pueden recibir argumentos igual que el script completo.

    Ejemplo:

    
    
    
    
    
    saludar() {
        echo "Hola $1"
    }
    
    saludar "Laura"
    

    Salida:

    
    
    
    
    
    Hola Laura
    

    Si deseas más parámetros:

    • $1 → primer argumento
    • $2 → segundo
    • $@ → todos

    5. Funciones que devuelven valores

    En Bash una función no “devuelve” valores como en otros lenguajes. Lo más común es:

    • Imprimir en pantalla
    • Guardar en variables
    • O usar return solo para códigos numéricos (0–255)

    5.1 Método estándar (captura por sustitución)

    
    
    
    
    
    sumar() {
        echo $(( $1 + $2 ))
    }
    
    resultado=$(sumar 3 4)
    echo "Resultado: $resultado"
    

    Salida:

    
    
    
    
    
    Resultado: 7
    

    5.2 return (solo numérico)

    
    
    
    
    
    comparar() {
        if [ $1 -gt $2 ]; then
            return 0
        else
            return 1
        fi
    }
    
    comparar 10 5
    
    if [ $? -eq 0 ]; then
        echo "El primero es mayor"
    fi
    

    6. Variables locales vs globales

    Por defecto, las variables en Bash son globales dentro del script.

    Para limitar su alcance dentro de la función, usa local:

    
    
    
    
    
    prueba() {
        local mensaje="Hola"
        echo "$mensaje"
    }
    
    prueba
    echo "$mensaje"  # Está vacía fuera de la función
    

    7. Organización modular del código

    A partir de ahora puedes:

    • Definir varias funciones en un mismo script
    • Usar funciones como “bloques” lógicos
    • Separar responsabilidades

    Ejemplo de script modular:

    
    
    
    
    
    mostrar_menu() {
        echo "1) Fecha"
        echo "2) Usuario"
        echo "3) Salir"
    }
    
    procesar_opcion() {
        case $1 in
            1) date ;;
            2) echo $USER ;;
            3) exit ;;
            *) echo "Opción inválida" ;;
        esac
    }
    
    mostrar_menu
    read -p "Opción: " op
    procesar_opcion $op
    

    8. Incluir funciones desde otros archivos (source)

    Esto permite crear “librerías” de funciones.

    Por ejemplo, en utils.sh:

    
    
    
    
    
    saludar() {
        echo "Hola $1"
    }
    

    En otro script:

    
    
    
    
    
    source utils.sh
    saludar "Carlos"
    

    Esto se usa para:

    • reutilizar código
    • crear módulos de funciones
    • evitar duplicar scripts

    9. Ejemplos

    Ejemplo 1: Función suma

    
    
    
    
    
    sumar() {
        echo $(( $1 + $2 ))
    }
    
    resultado=$(sumar 5 3)
    echo "Resultado: $resultado"
    

    Ejemplo 2: Librería simple

    log.sh:

    
    
    
    
    
    log() {
        echo "[LOG] $1"
    }
    

    test.sh:

    
    
    
    
    
    source log.sh
    log "Esto es una prueba"
    

    Ejemplo 3: Comprobador de archivos

    
    
    
    
    
    existe() {
        if [ -f "$1" ]; then
            echo "El archivo existe"
        else
            echo "No existe"
        fi
    }
    
    existe "/etc/passwd"
    

    Ejercicios propuestos

    Ejercicio 1:
    Crear un script matematicas.sh con funciones:

    • sumar
    • restar

    Cada función recibe 2 números y muestra el resultado.

    Ejercicio 2:
    Crear un script saludos.sh con una función saludar que reciba un nombre y muestre:

    
    
    
    
    
    Hola, <nombre>
    

    Ejercicio 3:
    Crear un script menu.sh con una función menu que muestre:

    1. Mostrar fecha
    2. Mostrar usuario
    3. Salir

    Y llame a otras funciones según la opción.

    Ejercicio 4:
    Crear un archivo utilidades.sh con una función log que agregue un mensaje a un archivo registro.txt.
    Luego crear un script test.sh que llame a log usando source.

    Soluciones

    ✅ Ejercicio 1 — matematicas.sh

    Enunciado:
    Crear un script matematicas.sh con funciones:

    • sumar
    • restar

    Cada función recibe 2 números y muestra el resultado.

    💡 Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: matematicas.sh
    # Funciones para sumar y restar dos números
    
    sumar() {
        # $1 y $2 son los parámetros de la función
        resultado=$(( $1 + $2 ))
        echo "La suma de $1 + $2 es $resultado"
    }
    
    restar() {
        resultado=$(( $1 - $2 ))
        echo "La resta de $1 - $2 es $resultado"
    }
    
    # Ejemplos de uso (se pueden sustituir por lectura de parámetros)
    sumar 10 5
    restar 10 5
    

    Si quieres que usen parámetros del script en lugar de valores fijos:

    
    
    
    
    
    #!/bin/bash
    
    sumar() {
        echo "La suma de $1 + $2 es $(( $1 + $2 ))"
    }
    
    restar() {
        echo "La resta de $1 - $2 es $(( $1 - $2 ))"
    }
    
    sumar "$1" "$2"
    restar "$1" "$2"
    

    ✅ Ejercicio 2 — saludos.sh

    Enunciado:
    Crear un script saludos.sh con una función saludar que reciba un nombre y muestre:

    Hola, <nombre>

    💡 Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: saludos.sh
    # Función saludar que recibe un nombre
    
    saludar() {
        nombre="$1"
        echo "Hola, $nombre"
    }
    
    # Ejemplo 1: pasar el nombre como parámetro al script
    # saludar "$1"
    
    # Ejemplo 2: pedirlo por teclado
    read -p "Introduce tu nombre: " nom
    saludar "$nom"
    

    ✅ Ejercicio 3 — menu.sh

    Enunciado:
    Crear un script menu.sh con una función menu que muestre:

    1. Mostrar fecha
    2. Mostrar usuario
    3. Salir

    Y llame a otras funciones según la opción.

    💡 Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: menu.sh
    # Menú con funciones para organizar el código
    
    mostrar_fecha() {
        echo "Fecha actual: $(date +"%Y-%m-%d %H:%M:%S")"
    }
    
    mostrar_usuario() {
        echo "Usuario actual: $USER"
    }
    
    menu() {
        echo "==== MENÚ ===="
        echo "1) Mostrar fecha"
        echo "2) Mostrar usuario"
        echo "3) Salir"
    }
    
    # Bucle para que el menú se repita hasta salir
    while true; do
        menu
        read -p "Elige una opción: " opcion
    
        case "$opcion" in
            1) mostrar_fecha ;;
            2) mostrar_usuario ;;
            3) echo "Saliendo..."; exit 0 ;;
            *) echo "Opción no válida" ;;
        esac
    
        echo # línea en blanco para separar
    done
    

    ✅ Ejercicio 4 — utilidades.sh + test.sh

    Enunciado:

    1. Crear un archivo utilidades.sh con una función log que agregue un mensaje a un archivo registro.txt.
    2. Crear un script test.sh que llame a log usando source.

    💡 utilidades.sh

    
    
    
    
    
    #!/bin/bash
    # Archivo: utilidades.sh
    # Contiene funciones reutilizables
    
    log() {
        mensaje="$1"
        fecha=$(date +"%Y-%m-%d %H:%M:%S")
        echo "[$fecha] $mensaje" >> registro.txt
    }
    

    Importante: este archivo no se ejecuta solo, se “incluye” desde otros scripts.


    💡 test.sh

    
    
    
    
    
    #!/bin/bash
    # Script: test.sh
    # Usa la función log de utilidades.sh
    
    # Cargar funciones desde utilidades.sh
    source ./utilidades.sh
    
    log "Inicio de la ejecución de test.sh"
    echo "He escrito una línea en registro.txt"
    
    # Puedes añadir más registros
    log "Otra acción importante realizada"
    

    Al ejecutar:

    
    
    
    
    
    chmod +x test.sh
    ./test.sh
    

    Contenido de registro.txt (ejemplo):

    
    
    
    
    
    [2026-01-11 19:30:01] Inicio de la ejecución de test.sh
    [2026-01-11 19:30:01] Otra acción importante realizada
    

  • 8. Entrada, Salida y Redirecciones

    En Bash, la forma en la que controlamos la entrada (lo que llega al programa) y la salida (lo que produce el programa) es crucial para automatizar tareas, guardar resultados, procesar archivos y comunicarnos entre procesos.

    Este módulo te enseña a usar redirecciones, pipes, flujos estándar y here documents, herramientas que convierten comandos simples en utilidades potentes.


    1. Los tres flujos estándar

    Todo comando tiene tres “canales”:

    FlujoNombreDescriptorSignificado
    stdinentrada estándar0Lo que el programa lee
    stdoutsalida estándar1Salida normal del programa
    stderrsalida de errores2Mensajes de error

    Ejemplo mental:

    • stdin: lo que escribes con el teclado
    • stdout: lo que ves normalmente en pantalla
    • stderr: errores que también aparecen en pantalla, pero son distintos

    2. Redirección de Salida (> y >>)

    Permite enviar la salida a un archivo en lugar de la pantalla.

    2.1 Sobrescribir (>)

    
    
    
    
    
    ls > archivos.txt
    

    Crea archivos.txt con la salida de ls.

    Si ya existía, lo sobrescribe.


    2.2 Añadir (>>)

    
    
    
    
    
    date >> registros.txt
    

    Añade la fecha al final sin borrar lo anterior.


    3. Redirección de Errores (2>)

    Para redirigir errores (stderr):

    
    
    
    
    
    comando 2> errores.log
    

    Ejemplo típico:

    
    
    
    
    
    ls /no/existe 2> errores.log
    

    errores.log contendrá:

    
    
    
    
    
    ls: no se puede acceder a '/no/existe': No existe el archivo o el directorio
    

    4. Redirección combinada (&>, 2>&1)

    A veces queremos juntar stdout + stderr.

    Hay dos métodos:

    4.1 Enviar ambos a un archivo

    
    
    
    
    
    comando &> salida.log
    

    4.2 Enviar stderr → stdout

    
    
    
    
    
    comando > salida.log 2>&1
    

    Eso significa:

    • > salida.log → stdout va a salida.log
    • 2>&1 → stderr va al mismo sitio que stdout

    5. Redirección de entrada (<)

    Permite que un comando lea datos desde un archivo.

    Ejemplo:

    
    
    
    
    
    sort < notas.txt
    

    Esto ordena las líneas de notas.txt y las muestra por pantalla.


    6. Pipes (|)

    Los pipes conectan programas entre sí: la salida de uno es la entrada del siguiente.

    Formato:

    
    
    
    
    
    comando1 | comando2
    

    Ejemplo clásico:

    
    
    
    
    
    ls /etc | grep ssh
    

    Interpretación:

    1. ls /etc lista todo
    2. grep ssh se queda con lo que contenga “ssh”

    Más ejemplos útiles:

    • Ver procesos y filtrar:
    
    
    
    
    
    ps aux | grep firefox
    
    • Contar líneas de un archivo:
    
    
    
    
    
    cat archivo.txt | wc -l
    
    • Buscar puertos en uso:
    
    
    
    
    
    netstat -tuln | grep ":80"
    

    7. Registro en archivos (logs)

    Para guardar salidas a un log sin perder errores:

    
    
    
    
    
    comando >> log.txt 2>&1
    

    Este patrón se usa muchísimo en servidores.


    8. Here Documents (<<)

    Permiten “pasar un texto” como entrada a un comando o script.

    Ejemplo:

    
    
    
    
    
    cat << EOF
    Hola mundo
    Esto es un here document
    EOF
    

    Salida:

    
    
    
    
    
    Hola mundo
    Esto es un here document
    

    Usos típicos: scripts SQL, correos, configuraciones, etc.

    Ejemplo con mysql:

    
    
    
    
    
    mysql -u root -p << EOF
    SHOW DATABASES;
    EOF
    

    9. Here Strings (<<<)

    Son como here documents pero para una sola cadena.

    Ejemplo:

    
    
    
    
    
    grep texto <<< "hola texto adiós"
    

    Resultado:

    
    
    
    
    
    hola texto adiós
    

    10. Ejemplos

    Ejemplo 1: Guardar un listado

    
    
    
    
    
    ls -l > listado.txt
    

    Ejemplo 2: Capturar errores

    
    
    
    
    
    find / -name "*.conf" 2> errores.txt
    

    Ejemplo 3: Recuento de procesos

    
    
    
    
    
    ps aux | wc -l
    

    Ejemplo 4: Ordenar archivo y guardar

    
    
    
    
    
    sort < nombres.txt > nombres_ordenados.txt
    

    Ejemplo 5: Script que registra salida y errores

    
    
    
    
    
    ./backup.sh >> backup.log 2>&1
    

    Ejercicios Propuestos

    Ejercicio 1:
    Crear un script lista.sh que liste /etc y guarde la salida en etc.txt.

    Ejercicio 2:
    Crear un script errores.sh que haga ls a un directorio que no existe y guarde el error en errores.log.

    Ejercicio 3:
    Crear un script red.sh que use un pipe para mostrar solo las líneas de ifconfig que contengan inet.

    Ejercicio 4:
    Crear un script ordenar.sh que ordene las líneas de ciudades.txt y las guarde en ordenadas.txt.

    Soluciones

    Ejercicio 1 — lista.sh

    Enunciado:
    Crear un script lista.sh que liste /etc y guarde la salida en etc.txt.

    💡 Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: lista.sh
    # Lista el contenido de /etc y lo guarda en etc.txt
    
    ls /etc > etc.txt
    echo "Listado guardado en etc.txt"
    

    Tras ejecutarlo:

    
    
    
    
    
    ./lista.sh
    

    etc.txt contendrá el listado del directorio /etc.


    Ejercicio 2 — errores.sh

    Enunciado:
    Crear un script errores.sh que haga ls a un directorio que no existe y guarde el error en errores.log.

    💡 Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: errores.sh
    # Genera un error de ls y lo guarda en errores.log
    
    ls /ruta/que/no/existe 2> errores.log
    echo "Error guardado en errores.log"
    

    Después de ejecutarlo:

    
    
    
    
    
    cat errores.log
    

    Salida esperada (puede variar según el idioma del sistema):

    
    
    
    
    
    ls: no se puede acceder a '/ruta/que/no/existe': No existe el archivo o el directorio
    

    Ejercicio 3 — red.sh

    Enunciado:
    Crear un script red.sh que use un pipe para mostrar solo las líneas de ifconfig que contengan inet.

    💡 Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: red.sh
    # Muestra solo las líneas con inet usando pipes
    
    ifconfig | grep inet
    

    Si usas ip a (más moderno que ifconfig), sería:

    
    
    
    
    
    #!/bin/bash
    ip a | grep inet
    

    Salida típica:

    
    
    
    
    
    inet 192.168.1.100/24 brd 192.168.1.255 scope global wlan0
    inet6 fe80::abcd:1234:5678:9101/64 scope link
    

    Ejercicio 4 — ordenar.sh

    Enunciado:
    Crear un script ordenar.sh que ordene las líneas de ciudades.txt y las guarde en ordenadas.txt.

    💡 Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: ordenar.sh
    # Ordena el archivo ciudades.txt y guarda el resultado
    
    sort < ciudades.txt > ordenadas.txt
    echo "Archivo ordenado guardado en ordenadas.txt"
    

    Si ciudades.txt contiene:

    
    
    
    
    
    Madrid
    Sevilla
    Barcelona
    Valencia
    

    El resultado en ordenadas.txt será:

    
    
    
    
    
    Barcelona
    Madrid
    Sevilla
    Valencia
    

    Otra opción

    Si quieres que los alumnos vean prácticas reales:

    Guardar logs sin machacar:

    
    
    
    
    
    ls /etc >> etc.log 2>&1
    

    Redirigir stdout + stderr a la vez:

    
    
    
    
    
    comando >> salida.log 2>&1
    

    Ejemplo realista: backup con logging:

    
    
    
    
    
    ./backup.sh >> backup.log 2>&1
    

    Esto se usa en cronjobs y servicios systemd.


    Resumen de herramientas usadas en los ejercicios

    HerramientaUso
    >redirigir salida, sobrescribe
    >>redirigir salida, añade
    2>redirigir errores
    ``
    <redirigir entrada desde archivo
    sortordenar líneas
    grepfiltrar texto

  • 9. Gestión de Archivos y Automatización del Sistema

    La automatización en Bash suele implicar mover, copiar, buscar, procesar y vigilar archivos, además de ejecutar tareas periódicas. En este módulo aprenderás a manipular archivos desde scripts y a automatizar acciones sobre el sistema, entrando ya en terreno de administrador serio.


    1. Comandos esenciales para gestionar archivos

    Bash no inventa nada aquí: usa comandos del sistema. Estos son tus martillos y destornilladores:

    ComandoUso
    cpCopiar archivos o directorios
    mvMover o renombrar
    rmBorrar archivos
    mkdirCrear directorios
    rmdirBorrar directorios vacíos
    touchCrear archivos vacíos o actualizar fecha
    chmodCambiar permisos
    chownCambiar propietario
    findBuscar archivos
    fileDetectar tipo de archivo

    Ejemplos rápidos:

    
    
    
    
    
    cp origen.txt destino.txt
    mv archivo.txt /tmp/
    rm viejo.txt
    mkdir respaldos
    touch notas.log
    

    2. Copias de seguridad (Backups) simples

    Un backup básico es copiar archivos o carpetas a otro lugar. Ejemplo:

    
    
    
    
    
    #!/bin/bash
    cp -r /home/usuario/documentos /home/usuario/respaldo/
    

    Añadir fecha para evitar sobreescritura:

    
    
    
    
    
    fecha=$(date +%Y-%m-%d)
    cp -r /home/usuario/documentos "/home/usuario/respaldo/doc_$fecha"
    

    Así tendrás:

    
    
    
    
    
    doc_2026-01-12/
    doc_2026-01-13/
    doc_2026-01-14/
    ...
    

    Automatización empieza aquí.


    3. Comprimir y descomprimir desde scripts

    Común en backups, logs y despliegue de software.

    HerramientaUso
    tarEmpaquetar/comprimir
    gzCompresión gzip
    zip/unzipCompresión zip

    Ejemplo:

    
    
    
    
    
    tar -czf respaldo.tar.gz /etc
    

    Explicación:

    • c → crear
    • z → comprimir con gzip
    • f → indicar nombre del archivo

    Descomprimir:

    
    
    
    
    
    tar -xzf respaldo.tar.gz
    

    4. Buscar archivos con find

    find es un radar. Busca por nombre, tamaño, fecha, permisos…

    Ejemplos útiles:

    Encontrar archivos por nombre:

    
    
    
    
    
    find /var/log -name "*.log"
    

    Por tamaño:

    
    
    
    
    
    find / -size +100M
    

    Por fecha (modificados hace menos de 1 día):

    
    
    
    
    
    find /tmp -mtime -1
    

    Por permisos inseguros:

    
    
    
    
    
    find /home -perm 777
    

    Puedes además ejecutar acciones:

    
    
    
    
    
    find /var/log -name "*.log" -exec gzip {} \;
    

    Esto comprime todos los .log.


    5. Analizar y procesar logs

    Los logs cuentan la historia del sistema. Para analizarlos usamos:

    • grep (buscar patrones)
    • cut (extraer columnas)
    • awk (procesar datos)
    • sed (modificar texto)

    Ejemplos básicos:

    Buscar errores:

    
    
    
    
    
    grep -i "error" /var/log/syslog
    

    Buscar IPs:

    
    
    
    
    
    grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}" acceso.log
    

    Contar líneas:

    
    
    
    
    
    wc -l /var/log/auth.log
    

    6. Automatización con cron

    cron ejecuta tareas programadas automáticamente.

    Editar tareas del usuario:

    
    
    
    
    
    crontab -e
    

    Formato:

    
    
    
    
    
    MIN HORA DIA MES DIASEM EJECUTABLE
    

    Ejemplos:

    Ejecutar un script cada día a las 23:00:

    
    
    
    
    
    0 23 * * * /home/user/scripts/backup.sh
    

    Cada 5 minutos:

    
    
    
    
    
    */5 * * * * /home/user/scripts/monitor.sh
    

    Ver tareas activas:

    
    
    
    
    
    crontab -l
    

    7. Automatización con systemd (modo pro)

    systemd permite ejecutar servicios y temporizadores.

    Estructura:

    • .service → define una acción
    • .timer → define cuándo se ejecuta

    Ejemplo de servicio:

    /etc/systemd/system/backup.service

    
    
    
    
    
    [Unit]
    Description=Backup Diario
    
    [Service]
    ExecStart=/usr/local/bin/backup.sh
    

    Ejemplo de timer:

    /etc/systemd/system/backup.timer

    
    
    
    
    
    [Unit]
    Description=Programa el backup diario
    
    [Timer]
    OnCalendar=daily
    
    [Install]
    WantedBy=timers.target
    

    Activar timer:

    
    
    
    
    
    systemctl enable --now backup.timer
    

    Ver logs:

    
    
    
    
    
    journalctl -u backup.service
    

    Los alumnos pueden ver cómo se automatiza un servidor real.


    8. Ejemplos

    Ejemplo 1: Backup con timestamp

    
    
    
    
    
    #!/bin/bash
    fecha=$(date +%Y-%m-%d_%H-%M)
    tar -czf backup_$fecha.tar.gz /home/alumno
    

    Ejemplo 2: Buscar archivos grandes

    
    
    
    
    
    #!/bin/bash
    find / -size +500M > grandes.txt
    

    Ejemplo 3: Comprimir logs viejos

    
    
    
    
    
    #!/bin/bash
    find /var/log -name "*.log" -mtime +7 -exec gzip {} \;
    

    Ejemplo 4: Filtrar errores de syslog

    
    
    
    
    
    #!/bin/bash
    grep -i "error" /var/log/syslog > errores.log
    

    Ejercicios Propuestos

    Ejercicio 1:
    Crear un script backup.sh que comprima /etc en un archivo etc.tar.gz.

    Ejercicio 2:
    Crear un script buscar.sh que busque archivos .conf en /etc y guarde la lista en conf.txt.

    Ejercicio 3:
    Crear un script errores.sh que filtre la palabra “error” del archivo /var/log/syslog y lo guarde en errores.log.

    Ejercicio 4:
    Crear una entrada cron que ejecute backup.sh todos los días a las 23:00.

    Ejercicio 5 (opcional pro):
    Crear un .service + .timer para ejecutar buscar.sh cada hora.


    Soluciones

    ✅ Ejercicio 1 — backup.sh

    Enunciado:
    Crear un script backup.sh que comprima /etc en un archivo etc.tar.gz.

    💡 Solución básica:

    
    
    
    
    
    #!/bin/bash
    # Script: backup.sh
    # Crea un backup comprimido del directorio /etc
    
    tar -czf etc.tar.gz /etc
    echo "Backup creado: etc.tar.gz"
    

    💡 Solución un poco mejor (con fecha):

    
    
    
    
    
    #!/bin/bash
    # Script: backup.sh
    # Crea un backup comprimido del directorio /etc con fecha
    
    fecha=$(date +%Y-%m-%d_%H-%M)
    archivo="etc_$fecha.tar.gz"
    
    tar -czf "$archivo" /etc
    echo "Backup creado: $archivo"
    

    ✅ Ejercicio 2 — buscar.sh

    Enunciado:
    Crear un script buscar.sh que busque archivos .conf en /etc y guarde la lista en conf.txt.

    💡 Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: buscar.sh
    # Busca archivos .conf en /etc y los guarda en conf.txt
    
    find /etc -type f -name "*.conf" > conf.txt
    echo "Listado de archivos .conf guardado en conf.txt"
    

    Si quieres que añada en lugar de sobrescribir:

    
    
    
    
    
    find /etc -type f -name "*.conf" >> conf.txt
    

    ✅ Ejercicio 3 — errores.sh

    Enunciado:
    Crear un script errores.sh que filtre la palabra “error” del archivo /var/log/syslog y lo guarde en errores.log.

    💡 Solución:

    
    
    
    
    
    #!/bin/bash
    # Script: errores.sh
    # Filtra líneas con 'error' en /var/log/syslog y las guarda en errores.log
    
    grep -i "error" /var/log/syslog > errores.log
    echo "Líneas con 'error' guardadas en errores.log"
    
    • -i → ignora mayúsculas/minúsculas (ERROR, Error, error…).

    ✅ Ejercicio 4 — Entrada de cron

    Enunciado:
    Crear una entrada cron que ejecute backup.sh todos los días a las 23:00.

    💡 Suposiciones:

    • El script está en: /home/usuario/scripts/backup.sh
    • Tiene permisos de ejecución: chmod +x backup.sh

    💡 Línea de crontab:

    Se edita con:

    
    
    
    
    
    crontab -e
    

    Y se añade:

    
    
    
    
    
    0 23 * * * /home/usuario/scripts/backup.sh >> /home/usuario/scripts/backup.log 2>&1
    

    Explicación rápida:

    • 0 23 * * * → a las 23:00 todos los días
    • >> backup.log 2>&1 → guarda salida y errores en un log (estilo “vida real”)

    ✅ Ejercicio 5 (opcional) — systemd service + timer

    Enunciado:
    Crear un .service + .timer para ejecutar buscar.sh cada hora.

    1️⃣ Script buscar.sh (por si acaso):

    
    
    
    
    
    #!/bin/bash
    # /usr/local/bin/buscar.sh
    
    find /etc -type f -name "*.conf" > /var/log/conf.txt
    

    Dar permisos:

    
    
    
    
    
    sudo chmod +x /usr/local/bin/buscar.sh
    

    2️⃣ Unidad de servicio: /etc/systemd/system/buscar.service

    
    
    
    
    
    [Unit]
    Description=Buscar archivos .conf en /etc
    
    [Service]
    Type=oneshot
    ExecStart=/usr/local/bin/buscar.sh
    

    3️⃣ Unidad de temporizador: /etc/systemd/system/buscar.timer

    
    
    
    
    
    [Unit]
    Description=Ejecutar buscar.sh cada hora
    
    [Timer]
    OnCalendar=hourly
    Persistent=true
    
    [Install]
    WantedBy=timers.target
    

    4️⃣ Activar y comprobar

    Recargar unidades:

    
    
    
    
    
    sudo systemctl daemon-reload
    

    Activar y arrancar el timer:

    
    
    
    
    
    sudo systemctl enable --now buscar.timer
    

    Ver estado:

    
    
    
    
    
    systemctl status buscar.timer
    

    Ver ejecuciones del servicio:

    
    
    
    
    
    journalctl -u buscar.service
    

  • 10. ¿QUÉ ES EL PATH?

    PATH es una variable de entorno que contiene una lista de directorios separados por dos puntos. Cuando escribes un comando como ls, el shell recorre esos directorios en orden buscando un ejecutable llamado “ls”. Si lo encuentra, lo ejecuta. Si no lo encuentra, error.

    Puedes verlo así:

    echo "$PATH"
    

    Ejemplo típico de salida:

    /usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/alumno/.local/bin

    El orden importa: el shell mira primero el primer directorio, luego el siguiente, y así.

    CREAR UN SCRIPT

    #!/bin/bash
    echo "Hola desde el sistema, $(whoami)!"
    

    Guardar como saludo.sh.

    –––––––

    ELEGIR DÓNDE VIVIRÁ
    Aquí hay dos caminos:

    A — Sólo para el usuario
    Usar ~/.local/bin (en muchas distros modernas este ya está en PATH).

    Si no existe:

    mkdir -p ~/.local/bin
    

    Luego mover el script ahí:

    mv saludo.sh ~/.local/bin/
    

    B — Para todo el sistema (requiere sudo)
    Usar /usr/local/bin:

    sudo mv saludo.sh /usr/local/bin/
    

    Esto hace que el script esté disponible para todos los usuarios

    –––––––

    PERMISOS
    El script debe tener el bit de ejecución activo. Si no:

    chmod +x ~/.local/bin/saludo.sh
    

    o si está en /usr/local/bin:

    sudo chmod +x /usr/local/bin/saludo.sh
    

    –––––––

    VERIFICAR SI EL DIRECTORIO YA ESTÁ EN EL PATH
    Para el caso ~/.local/bin, muchas distros lo incluyen. Comprobar con:

    echo "$PATH" | tr ':' '\n'
    

    Si se ve ~/.local/bin, listo.

    Si NO está, hay que añadirlo en ~/.bashrc o ~/.profile:

    echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
    source ~/.bashrc
    

    Aquí puedes introducir la distinción entre bashrc, profile y shells interactivos / no interactivos, pero sin entrar en guerra santa. A nivel pedagógico basta con que entiendan que esa línea hace persistente la ruta.

    –––––––

    EJECUTAR DESDE CUALQUIER PARTE
    Ve a cualquier carpeta:

    cd /tmp
    saludo.sh
    

    El script debería ejecutarse como cualquier comando del sistema. Si alguien intenta poner ./saludo.sh, puedes remarcar que ahora no hace falta, porque no necesita ruta explícita.

    –––––––

    OPCIONAL — QUITAR LA EXTENSIÓN
    Para que se sienta más “comando real”, renombrarlo:

    mv ~/.local/bin/saludo.sh ~/.local/bin/saludo
    

    Y ejecutarlo simplemente como:

    saludo
    

    La extensión .sh es cultural, no obligatoria, y que comandos del sistema no suelen llevar extensión.