Funciones: definición, return, local, ámbito de variables
Introducción
Las funciones permiten agrupar código reutilizable con un nombre. Evitan la duplicación, hacen los scripts más legibles y facilitan el mantenimiento. En bash, las funciones son ciudadanas de primera clase: se pueden pasar como argumentos y llamar recursivamente.
Definición de funciones
Hay dos sintaxis equivalentes:
# Sintaxis 1 (recomendada, POSIX)
nombre_funcion() {
# comandos
}
# Sintaxis 2 (bash específico)
function nombre_funcion {
# comandos
}
# Llamar a la función
nombre_funcion
nombre_funcion arg1 arg2
Las funciones deben definirse antes de ser llamadas. Se suelen poner al principio del script o
en un fichero de librería que se carga con source.
Argumentos de funciones
Las funciones reciben argumentos igual que los scripts: $1, $2... Dentro de la
función, estos valores son locales a ella y no interfieren con los del script principal.
#!/usr/bin/env bash
saludar() {
local NOMBRE="$1"
local IDIOMA="{$2:-es}"
case $IDIOMA in
es) echo "Hola, $NOMBRE" ;;
en) echo "Hello, $NOMBRE" ;;
fr) echo "Bonjour, $NOMBRE" ;;
*) echo "Hola, $NOMBRE (idioma desconocido)" ;;
esac
}
saludar "Juan"
saludar "John" "en"
saludar "Jean" "fr"
return — Código de salida de la función
return N establece el código de salida de la función (accesible con $?
después de llamarla). Solo acepta valores enteros de 0 a 255. No devuelve cadenas.
es_par() {
[ $(($1 % 2)) -eq 0 ] # la condición ya establece $? (0 o 1)
return $?
}
# Forma más corta (el return es implícito):
es_par() {
(( $1 % 2 == 0 ))
}
if es_par 4; then
echo "4 es par"
fi
es_par 7
echo "¿7 es par? Código: $?" # 1 (falso)
Devolver valores de cadena — capturar stdout:
La forma estándar de devolver un valor de texto desde una función es imprimirlo con echo
y capturar la salida con $():
mayusculas() {
echo "$1" | tr '[:lower:]' '[:upper:]'
}
RESULTADO=$(mayusculas "hola mundo")
echo "$RESULTADO" # HOLA MUNDO
local — Ámbito de variables
En bash, las variables son globales por defecto: una variable definida en una función
modifica la variable del mismo nombre en el script principal. Para evitar efectos colaterales, declarar las
variables de la función como local.
#!/usr/bin/env bash
VALOR="global"
sin_local() {
VALOR="modificado por sin_local" # modifica la global
}
con_local() {
local VALOR="local a la función" # no afecta a la global
echo "Dentro: $VALOR"
}
echo "Antes: $VALOR" # global
sin_local
echo "Después sin_local: $VALOR" # modificado por sin_local
con_local # Dentro: local a la función
echo "Después con_local: $VALOR" # modificado por sin_local (sin cambio)
Regla: declarar siempre las variables internas de una función como local
para evitar contaminar el ámbito global.
Librerías de funciones
Para reutilizar funciones en varios scripts, guardarlas en un fichero separado y cargarlo con
source:
# fichero: /usr/local/lib/mis_funciones.sh
log_info() {
echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') $*"
}
log_error() {
echo "[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $*" >&2
}
comprobar_root() {
if [ "$(id -u)" -ne 0 ]; then
log_error "Este script debe ejecutarse como root"
exit 1
fi
}
#!/usr/bin/env bash
# Cargar la librería
source /usr/local/lib/mis_funciones.sh
comprobar_root
log_info "Script iniciado"
# ...
log_info "Script finalizado correctamente"
Recursividad
factorial() {
local N=$1
if [ $N -le 1 ]; then
echo 1
else
local ANTERIOR=$(factorial $((N - 1)))
echo $((N * ANTERIOR))
fi
}
echo "5! = $(factorial 5)" # 5! = 120
La recursividad en bash es posible pero cara en rendimiento. Para cálculos intensivos, preferir herramientas
externas como awk o python3.