Funciones en Bash

funciones en bash

Las funciones en Bash son bloques de código que permiten organizar y estructurar mejor un script. No solo es útil sino necesario para no perdernos en nuestro propio código y reutilizarlo. En este post veremos algunos otro conceptos de variables que no abarcamos en su post, pero que ahora tiene sentido abordarlo.

¿Qué es una función en Bash?

Como en otros lenguajes, Bash también tiene el concepto de funciones y se usan para el mismo fin, con unas diferencias, sobre todo en su declaración y uso.

Sintaxis:

function nombre_de_funcion() {
    ...
}

En lo personal me gusta definir las funciones con la palabra function. Pero también podemos omitirla y solo escribir la firma:

nombre_de_funcion() {
    ...
}

Un ejemplo básico:

#!/bin/bash

# definición
function generar_aleatorio() {
    echo $RANDOM
}

# Llamada
generar_aleatorio

Usamos la variable $RANDOM para generar ese número aleatorio y cuando la llamamos, nos podemos dar cuenta que no usamos los paréntesis, solo el nombre de la función.

Parámetros en Bash

Las funciones en Bash pueden recibir parámetros, que permiten pasar argumentos a la función en el momento en que se llama, no en el momento de su definición. Raro, pero es así.

Ya en otro post vimos unas variables especiales que se encargan de leer los parámetros que son pasados a una función. Estas son:

  • $1, $2$n: representan los argumentos de la función.
  • $@ o $*: se utilizan para acceder a todos los argumentos pasados a la función.

Ya hemos utilizado muchas veces el comando echo, que nos sirve para imprimir mensajes en la pantalla, entonces podemos decir que en el comando echo "mensaje", “mensaje” es nuestro parámetro $1.

Veamos un ejemplo:

#!/bin/bash

# Definición
sumar() {
    resultado=$(( $1 + $2 ))
    echo "La suma de $1 y $2 es: $resultado"
}

sumar 5 7

La función sumar recibe dos argumentos y luego es llamada con los correspondientes valores 5 y 7.

Devolver valores en funciones de Bash

El ejemplo anterior es muy sencillo, pero en realidad, en su mayoría, las funciones nos regresarán valores, mismos que luego vas a usar para realizar otras operaciones. Por ejemplo, en nuestra función suma, yo necesito el valor, no un mensaje, porque no puedo tratar ese mensaje como un número.

En Bash, regresar un valor es medio raro, porque no podemos usar algo como return y luego el valor para asignarlo a una variable nueva. En su lugar, debemos imprimir el valor y asignar esa función a una variable para luego ser tratada.

Veamos el ejemplo de la suma:

#!/bin/bash

# Definición
sumar() {
    echo $(( $1 + $2 ))
}

sumar 5 7

Si hacemos esto, veremos por salida 12. Esto es porque al llamar la función, se ejecuta el comando echo, lo normal. Pero qué pasa si no quiero que se imprima, solo quiero tener ese valor para hacer algo más:

#!/bin/bash

# Definición
sumar() {
    echo $(( $1 + $2 ))
}

resultado=$(sumar 13 7)

if [ "$resultado" -ge 20 ]; then
    echo "$resultado Mayor o igual a 20"
else
    echo "$resultado menor a 20"
fi

Aquí evaluamos la función entre paréntesis $( ... ). Con esto evitamos la salida por sí misma y la capturamos en nuestra variable resultado para luego hacer una comparación con if e imprimir el resultado.

Dijimos que no podemos usar return. En realidad no es que no se pueda, lo que pasa que el funcionamiento no es como lo conocemos en otros lenguajes de programación.

Veamos un ejemplo de su uso:

#!/bin/bash

verificar_edad() {
    if [ $1 -ge 18 ]; then
        return 0
    else
        return 1
    fi
}

verificar_edad 20

if [ $? -eq 0 ]; then
    echo "Es mayor de edad."
else
    echo "Es menor de edad."
fi

Aquí usamos return para devolver 0 (en caso de que sea mayor de edad) o 1 (cuando sea menor de edad). Después de llamar la función vemos que en la condición usamos una variable especial. “$?" captura el último código de salida generado por la aplicación.

Alcance de las variables en Bash

En Bash existen las variables globales y las variables locales. Cuando declaras una variable dentro de una función, esta tiene el mismo alcance (scope) que todas las demás, no importa si están dentro o fuera, mientras se llamen igual se van a sobreescribir según se llamen y asignen dentro del script. Para evitarlo debe declararse como local.

Primero veamos un ejemplo de variable global:

#!/bin/bash

modificar_variable() {
    valor="modificar_variable"
}

valor="Original"
echo $valor

modificar_variable_2() {
    valor="modificar_variable_2"
}

modificar_variable
modificar_variable_2
echo $valor

La salida es:

Original
modificar_variable_2

En este ejemplo, las funciones modificar_variable y modificar_variable_2 tienen un variable llamada valor y en el alcance raíz también tenemos una variable con el mismo nombre, sin embargo, al momento de imprimir su valor, lo toma de la última función o asignación llamada.

NOTA: si nos damos cuenta, la variable del propio script (valor) se declara después de la función modificar_variable y aún así no impacta. Tendría el mismo efecto si se declara al inicio o en cualquier otro lugar.

Variables locales en Bash

Para prevenir el comportamiento anterior y asegurarnos que el scope no afecte otras variable con el mismo nombre, podemos usar la palabra local y su alcance estará limitado a la función.

Cuando se usa local, la variable dentro de la función tiene un alcance limitado solo a la función y no afecta a las variables fuera de ella:

#!/bin/bash

modificar_variable() {
    local valor="modificar_variable"
}

valor="Original"
echo $valor

modificar_variable
echo $valor

La salida es:

Original
Original

Acá la salida nos arroja dos veces “Original” ya que la variable valor dentro de modificar_variable está marcada como local y por lo tanto solo afecta dentro de esa función.

Pero veamos otro ejemplo un poco más complejo:

#!/bin/bash

modificar_variable() {
    local valor="modificar_variable"
    echo "local original: $valor"
    modificar_variable_2
    echo "local modificada: $valor"
}

modificar_variable_2() {
    valor="modificar_variable_2"
}

valor="Original"

modificar_variable
echo $valor

La salida es:

local original: modificar_variable
local modificada: modificar_variable_2
Original

Como vemos, dentro de modificar_variable tenemos nuestra variable declarada como local y luego llamamos a la otra función modificar_variable_2. El valor cambia al llamar la función porque básicamente le estamos diciendo que todo lo que se haga con valor se afectará mientras el flujo continúe dentro de la función.

Esto cambiaría si en la función modificar_variable_2 también declaramos valor como local y tendríamos la salida:

al original: modificar_variable
local modificada: modificar_variable
Original

Funciones externas en Bash

Lo normal cuando programamos algo es no tener toooodo el código dentro de un mismo archivo, y por lo general lo separamos en varios que agrupen funcionalidad. Luego estos serán llamados por nuestro script principal.

Hagamos un ejemplo con un caso de uso en el que creamos una “librería” que haga operaciones matemáticas y luego en nuestro script principal mandamos llamar una función:

Archivo math.sh:

#!/bin/bash

function suma() {
    echo $(( $1 + $2 ))
}

Archivo principal main.sh:

#!/bin/bash

# Llamar a nuestra librería
source math.sh

resultado=$(suma 13 73)

echo "SUMA: $resultado"

Con esto terminamos este tema muy importante en cualquier lenguaje de programación.

¡Gracias por leer!


Posted

in

, ,

by