Crear scripts bash: la guía mínima

última modificación:

A lo largo de los artículos anteriores hemos usado comandos sueltos en la consola. Cuando una secuencia de comandos se repite, lo natural es meterla en un script bash para no tener que escribirla cada vez.

Un script bash es un archivo de texto que empieza con la línea:

#!/bin/bash

Esta primera línea (el «shebang») le dice al sistema qué intérprete usar. A continuación escribimos los comandos igual que en la consola.

Variables y condicionales

Un script que comprueba si un servicio está corriendo y lo arranca si no:

#!/bin/bash

SERVICIO="apache2"

if ! sudo service $SERVICIO status > /dev/null 2>&1; then
    sudo service $SERVICIO start
    echo "$SERVICIO arrancado"
fi

La variable SERVICIO hace el script reutilizable para cualquier servicio. La condición usa ! para invertir el resultado: si status falla (servicio parado), entra en el bloque y lo arranca.

Bucles

Un script que renombra en lote archivos .jpeg a .jpg en el directorio actual:

#!/bin/bash

for archivo in *.jpeg; do
    [ -f "$archivo" ] || continue
    nuevo="${archivo%.jpeg}.jpg"
    mv "$archivo" "$nuevo"
    echo "Renombrado: $archivo$nuevo"
done

${archivo%.jpeg} elimina el sufijo .jpeg del nombre (una sustitución de parámetro de bash que evita llamar a sed para algo tan simple).

Hacerlo ejecutable

chmod 755 mi-script.sh

Y para ejecutarlo:

./mi-script.sh

O copiarlo a /usr/local/bin/ para tenerlo disponible en cualquier directorio.

Códigos de salida

Cuando un script termina, devuelve un número al sistema: 0 significa éxito, cualquier otro valor significa error. $? contiene el código del último comando ejecutado:

ls /etc/hosts > /dev/null 2>&1
echo $?   # 0 (el archivo existe)

ls /no-existe > /dev/null 2>&1
echo $?   # distinto de 0 (el archivo no existe)

En un script propio se usa exit para fijar el código explícitamente:

#!/bin/bash

ARCHIVO=$1
if [ ! -f "$ARCHIVO" ]; then
    echo "Error: $ARCHIVO no existe" >&2
    exit 1
fi
echo "OK: $ARCHIVO encontrado"
exit 0

exit 1 señala que algo falló; exit 0 confirma que todo fue bien. Esto permite encadenar scripts con && o comprobar el resultado desde otro script.

Depuración

bash -x muestra cada comando antes de ejecutarlo, útil para entender qué va mal:

bash -x mi-script.sh

Para scripts en cron

Dos reglas imprescindibles si el script lo ejecuta cron:

  • Usar siempre rutas absolutas (cron tiene un PATH reducido)
  • Redirigir errores si no queremos recibir correos: comando 2>/dev/null