Categoría: Sistemas

  • 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.

  • 11. [Reto] Bash Incremental: Aprender Shell a Golpes de Ejemplos

    11. [Reto] Bash Incremental: Aprender Shell a Golpes de Ejemplos

    En esta práctica trabajarás con una colección de scripts en Bash orientados a tareas básicas de automatización y administración en Linux. El objetivo es que ejecutes y analices cada uno de los scripts en tu terminal para comprender su funcionamiento y el efecto que producen.

    Tareas a realizar

    1. Copia todos los scripts proporcionados en tu máquina Linux (física o virtual).
    2. Asegúrate de que cada script tenga permisos de ejecución usando: chmod +x nombre_script.sh
    3. Ejecuta cada script desde la terminal y observa el resultado.
    4. Modifica al menos 3 scripts para adaptarlos a una variante que tenga sentido. Por ejemplo:
      • Cambiar rutas
      • Cambiar comandos
      • Añadir opciones
      • Añadir colores o logs

    La línea del “shebang” (#!)

    #!/bin/bash
    #!/usr/bin/env bash

    La diferencia tiene que ver con flexibilidad vs. certeza.

    Cuando pones #!/bin/bash estás diciendo “usa Bash que está en /bin/bash”.
    Eso asume que la ruta es exactamente esa. En muchas distros Linux es verdad, en macOS a veces también, pero en otras no. Por ejemplo, en sistemas BSD, en instalaciones personalizadas, o si manejas múltiples versiones de Bash instaladas desde brew, nix, etc., /bin/bash puede no existir o no ser el Bash que quieres.

    La alternativa #!/usr/bin/env bash juega una carta distinta:
    env busca ejecutables en el PATH del usuario, encuentra dónde está bash y lo lanza.
    Es como decir: “búscame un Bash válido en la ruta del sistema y úsalo”.
    Eso lo vuelve más portátil y adaptable, sobre todo en entornos raros, macOS moderno, contenedores, virtual environments y setups educativos donde Bash no está donde uno espera.

    El resumen práctico:

    #!/bin/bash = certero pero rígido. Si no existe esa ruta, falla.
    #!/usr/bin/env bash = más portable y respetuoso del PATH, útil cuando no conoces el entorno.

    Ejemplo 1: “Hola, soy un script”
    Propósito: variables y echo.

    #!/usr/bin/env bash
    
    nombre="Antonio"
    echo "Hola, $nombre"
    echo "Estoy en el directorio: $(pwd)"
    

    Concepto nuevo: variables y comandos incrustados $(...).


    Ejemplo 2: “Si me pasas un nombre, lo uso”
    Propósito: argumentos $1.

    #!/usr/bin/env bash
    
    if [ -z "$1" ]; then
      echo "Uso: $0 <nombre>"
      exit 1
    fi
    
    echo "Hola, $1"
    

    Concepto nuevo: if mínimo, chequeo de argumentos y exit.


    Ejemplo 3: “Saludo a varios”
    Propósito: recorrer argumentos (for).

    #!/usr/bin/env bash
    
    if [ "$#" -eq 0 ]; then
      echo "Uso: $0 nombre1 nombre2 ..."
      exit 1
    fi
    
    for persona in "$@"; do
      echo "Hola, $persona"
    done
    

    Concepto nuevo: for y "$@" (todos los argumentos).


    Ejemplo 4: “Saludo según hora”
    Propósito: condicionales compuestos.

    #!/usr/bin/env bash
    
    hora=$(date +%H)
    
    if [ "$hora" -lt 12 ]; then
      saludo="Buenos días"
    elif [ "$hora" -lt 20 ]; then
      saludo="Buenas tardes"
    else
      saludo="Buenas noches"
    fi
    
    echo "$saludo, $(whoami)"
    

    Concepto nuevo: elif, comparaciones numéricas y uso de comandos para info del sistema.


    Pequeño ejemplo 5: “Función que loguea cosas”
    Propósito: funciones y reutilización.

    #!/usr/bin/env bash
    
    log(){
      echo "[$(date +%H:%M:%S)] $1"
    }
    
    log "Iniciando proceso"
    sleep 1
    log "Proceso terminado"
    

    Concepto nuevo: funciones y timestamps.


    Pequeño ejemplo 6: “Descargo URLs de una lista”
    Propósito: arrays, loops y llamar programas externos.

    Archivo urls.txt de ejemplo:

    https://example.org
    https://wikipedia.org
    

    Script:

    #!/usr/bin/env bash
    
    while read -r url; do
      [ -z "$url" ] && continue
      echo "Descargando $url"
      curl -s -O "$url"
    done < urls.txt
    

    Concepto nuevo: while read, redirección y pequeñas automatizaciones.


    Ejemplo 7: “Contador de líneas de código por extensión”
    Propósito: bucles, condicionales, comandos, pipes.

    #!/usr/bin/env bash
    
    if [ -z "$1" ]; then
      echo "Uso: $0 <directorio>"
      exit 1
    fi
    
    dir="$1"
    for ext in sh py js php; do
      total=$(find "$dir" -type f -name "*.$ext" -print0 | xargs -0 cat 2>/dev/null | wc -l)
      echo "$ext: $total líneas"
    done
    

    Concepto nuevo: usar herramientas externas y procesar resultados.


    Ejemplo 8: “Menú interactivo mínimo”
    Propósito: select y control básico de flujo.

    #!/usr/bin/env bash
    
    select opcion in Fecha Usuario Salir; do
      case "$opcion" in
        Fecha) date ;;
        Usuario) whoami ;;
        Salir) echo "Adiós"; break ;;
        *) echo "Opción no válida" ;;
      esac
    done
    

    Concepto nuevo: select + case.


    Pequeño ejemplo 9: “Backup comprimido con timestamp”
    Propósito: combinación de todo para algo útil.

    #!/usr/bin/env bash
    
    origen="$1"
    destino="$2"
    
    if [ -z "$origen" ] || [ -z "$destino" ]; then
      echo "Uso: $0 <directorio_origen> <directorio_destino>"
      exit 1
    fi
    
    fecha=$(date +%Y%m%d_%H%M%S)
    archivo="$destino/backup_$fecha.tar.gz"
    
    echo "Creando backup de $origen en $archivo..."
    tar -czf "$archivo" "$origen"
    echo "Backup creado."

    Ejemplo 10: Crear estructura de carpetas de proyecto

    Idea: Montar la estructura típica de un proyecto sin ir haciendo mkdir a mano.

    #!/usr/bin/env bash
    
    if [ -z "$1" ]; then
      echo "Uso: $0 <nombre_proyecto>"
      exit 1
    fi
    
    PROYECTO="$1"
    
    mkdir -p "$PROYECTO"/{src,bin,logs,tmp,docs}
    
    echo "Proyecto creado en: $PROYECTO"
    ls -R "$PROYECTO"
    

    Ejemplo 11: Buscar una palabra en todos los .log de un directorio

    Idea: Mini-grep para revisar logs del sistema o de una app.

    #!/usr/bin/env bash
    
    DIR="${1:-/var/log}"
    CADENA="$2"
    
    if [ -z "$CADENA" ]; then
      echo "Uso: $0 <directorio_logs> <cadena_a_buscar>"
      echo "Ejemplo: $0 /var/log error"
      exit 1
    fi
    
    echo "Buscando '$CADENA' en *.log de $DIR..."
    grep -Rni --include="*.log" "$CADENA" "$DIR"
    

    Ejemplo 12: Top 5 archivos más grandes de un directorio

    Idea: Visualizar qué archivos se están comiendo el disco.

    #!/usr/bin/env bash
    
    DIR="${1:-.}"
    
    echo "Top 5 archivos más grandes en: $DIR"
    du -ah "$DIR" 2>/dev/null | sort -h | tail -n 5
    

    Ejemplo 13: Aviso sencillo de uso de disco

    Idea: Script que comprueba / y avisa si pasa de cierto porcentaje.

    #!/usr/bin/env bash
    
    LIMITE=80  # porcentaje
    
    uso=$(df -h / | awk 'NR==2 {gsub("%","",$5); print $5}')
    
    echo "Uso actual de / : $uso%"
    
    if [ "$uso" -gt "$LIMITE" ]; then
      echo "⚠ Atención: uso de disco por encima de ${LIMITE}%"
    else
      echo "Todo OK, por debajo de ${LIMITE}%"
    fi
    

    Ejemplo 14: Copia rápida de syslog con timestamp

    Idea: Guardar copia de seguridad de un log del sistema en el HOME del usuario.

    #!/usr/bin/env bash
    
    ORIGEN="/var/log/syslog"
    DEST="$HOME"
    
    if [ ! -f "$ORIGEN" ]; then
      echo "No existe $ORIGEN (en algunas distros es /var/log/messages)"
      exit 1
    fi
    
    FECHA=$(date +%Y%m%d_%H%M%S)
    COPIA="$DEST/syslog_$FECHA.log"
    
    cp "$ORIGEN" "$COPIA"
    
    echo "Copia creada en: $COPIA"
    

    Ejemplo 15: Ping-monitor cutre pero efectivo

    Idea: Comprobar conectividad a un host cada pocos segundos.

    #!/usr/bin/env bash
    
    HOST="${1:-8.8.8.8}"
    
    echo "Monitoreando ping a $HOST (Ctrl+C para salir)"
    
    while true; do
      if ping -c 1 -W 1 "$HOST" >/dev/null 2>&1; then
        echo "[$(date +%H:%M:%S)] $HOST está accesible"
      else
        echo "[$(date +%H:%M:%S)] ⚠ $HOST NO responde"
      fi
      sleep 3
    done
    

    Ejemplo 16: Listar usuarios del sistema con su shell

    Idea: Leer /etc/passwd y mostrar usuario + shell. Tocado sistema pero muy didáctico.

    #!/usr/bin/env bash
    
    echo "Usuarios del sistema y su shell:"
    echo "--------------------------------"
    
    while IFS=: read -r user _ _ _ _ _ shell; do
      echo "$user -> $shell"
    done < /etc/passwd
    

    Ejemplo 17: Comprobar si un servicio está activo (systemd)

    Idea: Ver el estado de un servicio con systemctl.

    #!/usr/bin/env bash
    
    if [ -z "$1" ]; then
      echo "Uso: $0 <nombre_servicio>"
      echo "Ejemplo: $0 apache2"
      exit 1
    fi
    
    SERV="$1"
    
    estado=$(systemctl is-active "$SERV" 2>/dev/null)
    
    if [ "$estado" = "active" ]; then
      echo "✅ El servicio $SERV está ACTIVO"
    elif [ "$estado" = "inactive" ]; then
      echo "⏸ El servicio $SERV está INACTIVO"
    else
      echo "❓ El servicio $SERV no existe o no usa systemd (estado: $estado)"
    fi
    

    Ejemplo 18: Renombrar archivos añadiendo un prefijo

    Idea: Jugar con nombres de archivos y bucles. Muy útil para fotos, prácticas, etc.

    #!/usr/bin/env bash
    
    if [ "$#" -lt 2 ]; then
      echo "Uso: $0 <prefijo> <archivos...>"
      echo "Ejemplo: $0 practica1 *.txt"
      exit 1
    fi
    
    PREFIJO="$1"
    shift
    
    for fichero in "$@"; do
      if [ -f "$fichero" ]; then
        nuevo="${PREFIJO}_$fichero"
        mv "$fichero" "$nuevo"
        echo "$fichero -> $nuevo"
      else
        echo "Saltando $fichero (no es un archivo)"
      fi
    done
    

    Ejemplo 19: Menú para ver info básica del sistema

    Idea: Un menú simple que llame a varios comandos de sistema.

    #!/usr/bin/env bash
    
    mostrar_sistema() {
      echo "Sistema:"
      uname -a
    }
    
    mostrar_cpu() {
      echo "CPU:"
      lscpu | head -n 10
    }
    
    mostrar_mem() {
      echo "Memoria:"
      free -h
    }
    
    mostrar_disks() {
      echo "Discos:"
      df -h
    }
    
    PS3="Elige una opción (1-5): "
    
    select opcion in "Info sistema" "CPU" "Memoria" "Discos" "Salir"; do
      case "$REPLY" in
        1) mostrar_sistema ;;
        2) mostrar_cpu ;;
        3) mostrar_mem ;;
        4) mostrar_disks ;;
        5) echo "Adiós"; break ;;
        *) echo "Opción no válida" ;;
      esac
    done
    

  • Actividad – Completa Script de NMAP

    Actividad – Completa Script de NMAP

    Hacer un script de Bash que reúna los comandos y opciones más útiles de nmap, organizado en funciones y con un menú para que practiquen if/else, funciones, lectura de parámetros y buenas prácticas.y

    Completa el script, para ello se te propociona el menú y el conjunto de funciones utilizadas. Debes completarlo para que tenga un funcionamiento correcto

    # Menú principal
    main_menu() {
    
      while true; do
        clear
        echo "========================================"
        echo "       NMAP HELPER - MENÚ EDUCATIVO     "
        echo "========================================"
        echo "1) Ping scan (descubrir hosts vivos)"
        echo "2) TCP SYN top 100 (--top-ports 100 -sS)"
        echo "3) TCP connect scan y puertos personalizados (-sT -p)"
        echo "4) Detección de servicios y versiones (-sV -sC)"
        echo "5) Detección de SO (-O)"
        echo "6) Escaneo UDP (-sU)"
        echo "7) Escaneo agresivo (-A)"
        echo "8) NSE scripts (--script)"
        echo "9) Salida en formatos (-oN, -oX, -oG)"
        echo "10) Escaneo sin ping (-Pn)"
        echo "11) Crea tu propia opción para namp"
        echo "12) Salir"
        echo "========================================"
        read -p "Elige opción [1-12]: " opt

    En todas las opciones al final debe dar el mensaje de legalidad de uso.

    usage_note() {
      cat <<EOF
    
    IMPORTANTE (ÉTICA Y LEGAL):
    - Solo escanea equipos y redes que sean de tu propiedad o para los que tengas permiso explícito.
    - El escaneo puede ser detectado por IDS/IPS y puede tener consecuencias en redes de producción.
    - No uses estos comandos en redes públicas sin autorización.
    
    EOF
    }