Guía

Script bash para principiantes: primer script, variables, condiciones, bucles y cron

Actualizado: · Skillaria.Top

Un script bash es un archivo de texto con comandos de shell que empieza por la línea #!/bin/bash, recibe permiso de ejecución con chmod +x y se lanza como ./script.sh. Los scripts usan variables, los argumentos $1 y $2, condiciones if y bucles for y while; la ejecución periódica se configura con crontab -e.

Un script bash es un archivo de texto con comandos que, de otro modo, escribiría uno a uno en la terminal. El script empieza con la línea shebang #!/bin/bash, recibe permiso de ejecución con chmod +x y se lanza como ./script.sh. Esta guía de script bash para principiantes le acompaña desde la primera línea hasta la ejecución programada: variables, argumentos, condiciones, bucles, gestión de errores y cron.

Su primer script bash en un minuto

Cree un archivo en cualquier editor, por ejemplo nano:

nano hola.sh
#!/bin/bash
# Primer script: saludo e información básica del sistema
echo "Hola, $USER!"
echo "Hoy: $(date +%Y-%m-%d)"
echo "Está en: $(pwd)"

Guarde (Ctrl+O, Intro, Ctrl+X), dé permiso de ejecución y lance el script:

$ chmod +x hola.sh
$ ./hola.sh
Hola, alice!
Hoy: 2026-10-12
Está en: /home/alice

Las líneas que empiezan por # son comentarios. $(comando) inserta en la línea la salida de un comando.

Shebang: para qué sirve la primera línea

La línea #!/bin/bash indica al sistema con qué intérprete ejecutar el archivo. Sin ella, el script se ejecuta con la shell que esté disponible; en algunos sistemas /bin/sh no es bash, sino el más sencillo dash, donde algunas construcciones no funcionan.

También es habitual la variante #!/usr/bin/env bash: busca bash en el PATH, lo cual resulta útil si bash no está instalado en /bin.

Cómo ejecutar un script y por qué ./

Hay dos formas:

  • ./hola.sh — necesita el shebang y el permiso x. El prefijo ./ es obligatorio, porque el directorio actual no está en el PATH.
  • bash hola.sh — no requiere permiso de ejecución, el intérprete se indica de forma explícita.

Si ve command not found sin ./, o Permission denied sin chmod +x, esas son exactamente las dos causas. Para llamar a sus scripts por nombre desde cualquier lugar, guárdelos en ~/bin o en /usr/local/bin.

Variables

Una variable se asigna sin espacios alrededor del = y se lee con $:

#!/bin/bash
nombre="copia"
directorio="/var/backups"
hoy=$(date +%F)

echo "Archivo: ${directorio}/${nombre}-${hoy}.tar.gz"

Las llaves separan el nombre de la variable del texto que la rodea. La línea nombre = "copia" con espacios es un error: bash intentará ejecutar un comando llamado nombre.

Las comillas importan

Entre comillas dobles las variables se sustituyen; entre comillas simples, no. Conviene casi siempre poner las variables entre comillas dobles, porque de lo contrario un nombre de archivo con espacios se dividirá en dos argumentos.

archivo="mi informe.txt"
rm $archivo      # error: intentará borrar «mi» e «informe.txt»
rm "$archivo"    # correcto
echo '$HOME'     # muestra literalmente $HOME
echo "$HOME"     # muestra /home/alice

Variables de entorno

Variables como $HOME, $USER y $PATH las define el sistema. Su propia variable se pasa a los procesos hijos con export. Los ajustes permanentes del entorno van en ~/.bashrc o ~/.profile.

Argumentos del script

Los valores que se pasan al lanzar el script están disponibles como $1, $2, etc.

VariableQué contiene
$0el nombre del script
$1, $2…el primer, el segundo argumento
$#el número de argumentos
"$@"todos los argumentos, cada uno por separado
$?el código de salida del último comando
$$el PID del script actual
#!/bin/bash
echo "El script $0 ha recibido $# argumento(s)"
echo "El primero: $1"
$ ./argumentos.sh nginx 80
El script ./argumentos.sh ha recibido 2 argumento(s)
El primero: nginx

La entrada del usuario se lee con el comando read: read -p "Introduzca el nombre: " nombre.

Condiciones if

Cada comando devuelve un código de salida: 0 significa éxito, cualquier otro valor un error. La construcción if comprueba precisamente ese código. Para las comparaciones se usa [[ ... ]]; los espacios dentro de los corchetes son obligatorios.

#!/bin/bash
if [[ $# -eq 0 ]]; then
    echo "Uso: $0 <directorio>"
    exit 1
fi

if [[ -d "$1" ]]; then
    echo "El directorio $1 existe"
elif [[ -f "$1" ]]; then
    echo "$1 es un archivo, no un directorio"
else
    echo "$1 no encontrado"
fi
ComprobaciónSignificado
-f archivoexiste un archivo normal
-d directorioexiste un directorio
-e rutala ruta existe
-x archivoel archivo es ejecutable
-z "$var" / -n "$var"la cadena está vacía / no vacía
"$a" == "$b", !=comparación de cadenas
-eq -ne -lt -le -gt -gecomparación numérica

También se puede comprobar cualquier comando directamente:

if systemctl is-active --quiet nginx; then
    echo "nginx está en marcha"
else
    echo "nginx está detenido"
fi

Para muchas opciones resulta cómodo case:

case "$1" in
    start)   echo "Iniciando" ;;
    stop)    echo "Deteniendo" ;;
    *)       echo "Comando desconocido: $1"; exit 1 ;;
esac

Bucles for y while

for: recorrer una lista

for equipo in web1 web2 db1; do
    echo "Comprobando $equipo"
    ping -c 1 -W 1 "$equipo" > /dev/null && echo "  accesible" || echo "  inaccesible"
done

for archivo in /var/log/*.log; do
    echo "$archivo: $(wc -l < "$archivo") líneas"
done

for i in {1..5}; do
    echo "Intento $i"
done

while: mientras la condición se cumpla

Un ejemplo clásico es leer un archivo línea a línea:

while read -r usuario; do
    echo "Usuario: $usuario"
done < usuarios.txt

Y esperar a que un servicio arranque:

contador=0
until curl -sf http://localhost:8080/health > /dev/null; do
    contador=$((contador + 1))
    if [[ $contador -ge 10 ]]; then
        echo "El servicio no arrancó"
        exit 1
    fi
    sleep 3
done
echo "El servicio está listo"

La aritmética en bash se escribe entre dobles paréntesis: $((a + b)). Solo funciona con números enteros.

Funciones

El código repetido se agrupa en funciones. Dentro de una función, los argumentos son los mismos $1, $2, y local evita que una variable salga de la función.

registro() {
    local nivel="$1"; shift
    echo "$(date '+%F %T') [$nivel] $*"
}

registro INFO "Comienza la copia de seguridad"
registro ERROR "Sin espacio en disco"

Gestión de errores: set -euo pipefail

Por defecto, bash continúa tras un comando fallido: un script de copia de seguridad puede terminar «con éxito» sin haber copiado nada. Por eso al inicio de los scripts se suele añadir un modo estricto:

#!/bin/bash
set -euo pipefail
  • -e — detenerse ante el primer error.
  • -u — tratar el uso de una variable no definida como error (protege frente a rm -rf "$DIR/" con DIR vacío).
  • -o pipefail — una tubería falla si falla cualquiera de sus partes.

Para depurar, ejecute el script como bash -x script.sh: bash muestra cada comando antes de ejecutarlo. La utilidad shellcheck ayuda a encontrar errores típicos antes de lanzar el script.

Ejemplo práctico: un script de copia de seguridad

#!/bin/bash
set -euo pipefail

ORIGEN="${1:-/var/www}"
DESTINO="/var/backups/sitio"
DIAS_CONSERVAR=7
MARCA=$(date +%F_%H-%M)

mkdir -p "$DESTINO"
tar -czf "$DESTINO/sitio-$MARCA.tar.gz" -C "$(dirname "$ORIGEN")" "$(basename "$ORIGEN")"
echo "Archivo creado: $DESTINO/sitio-$MARCA.tar.gz"

# borrar las copias más antiguas que DIAS_CONSERVAR días
find "$DESTINO" -name "sitio-*.tar.gz" -mtime +"$DIAS_CONSERVAR" -delete

La expresión ${1:-/var/www} significa «el primer argumento, o /var/www si no hay ninguno». Guarde el script como /usr/local/bin/backup-sitio.sh y hágalo ejecutable: sudo chmod +x /usr/local/bin/backup-sitio.sh.

Ejecución programada: cron

Cron es el servicio que lanza comandos según un calendario. Las tareas de un usuario se editan con crontab -e, se listan con crontab -l, y las de root con sudo crontab -e.

Una línea de tarea consta de cinco campos de tiempo y el comando:

# minuto hora día_del_mes mes día_de_la_semana comando
30 2 * * * /usr/local/bin/backup-sitio.sh >> /var/log/backup.log 2>&1
ProgramaciónCuándo se ejecuta
*/5 * * * *cada 5 minutos
0 * * * *al inicio de cada hora
30 2 * * *todos los días a las 02:30
0 9 * * 1-5de lunes a viernes a las 09:00
0 3 1 * *el día 1 de cada mes a las 03:00
@rebootuna vez tras el arranque

Por qué un script funciona a mano pero no en cron

  • Entorno distinto. Cron ejecuta las tareas con un PATH mínimo y sin su ~/.bashrc. Escriba rutas completas a comandos y archivos, o defina PATH al inicio de la crontab.
  • Directorio actual distinto. La tarea arranca en el directorio personal, no donde está el script. Use rutas absolutas.
  • El carácter %. En una crontab, el signo % significa salto de línea, así que date +%F escrito directamente en la tarea debe escaparse como \%. Es más sencillo meter el comando en un script.
  • La salida se pierde. Redirija la salida a un registro (>> archivo 2>&1); si no, no verá los errores. Las ejecuciones de cron se consultan con journalctl -u cron (en sistemas tipo RHEL, el servicio se llama crond).

En sistemas con systemd, los timers son una alternativa a cron: escriben la salida en el journal y pueden recuperar las ejecuciones perdidas.

Resumen

Un script bash para principiantes es un archivo que empieza con el shebang #!/bin/bash, tiene permiso de ejecución y contiene una secuencia de comandos. Añada variables entre comillas, una comprobación de argumentos con if, los bucles for y while y el modo estricto set -euo pipefail, y tendrá una herramienta de automatización fiable que cron puede ejecutar periódicamente. Los scripts bash, el entorno y cron se explican paso a paso y con práctica en nuestro curso de Linux.

Preguntas frecuentes

¿En qué se diferencia bash de sh?

sh es la shell POSIX estándar, mientras que bash es su versión ampliada, con arrays, dobles corchetes y otras comodidades. Un script que usa construcciones de bash debe ejecutarse con bash, no con sh.

¿Qué extensión debe tener un script bash?

Linux no mira la extensión: el intérprete lo determina el shebang. La extensión .sh es solo una convención para indicar a las personas que se trata de un script.

¿Cómo paso una contraseña a un script de forma segura?

No la pase como argumento: los argumentos son visibles para otros usuarios en ps. Use una variable de entorno cargada desde un archivo con permisos 600, o read -s para introducirla sin mostrarla.

¿Cómo compruebo que el script se ejecuta como root?

Compare el identificador de usuario con cero: if [[ $EUID -ne 0 ]]; then echo "Se requiere root"; exit 1; fi.

¿Cómo ejecuto un script en segundo plano para que no se detenga al cerrar la sesión SSH?

Use nohup ./script.sh &, una sesión de tmux o screen, y para un funcionamiento permanente convierta el script en un servicio systemd.

Aprende este tema en vídeo

Este tema se explica a fondo y con práctica en el curso «Linux: с нуля до уверенного администрирования».

Ir al curso