Tracks
/
Bash
Bash
/
Temario
/
Funciones
Fu

Funciones en Bash

{one: "1 ejercicio", many: "%{count} ejercicios", other: "%{count} ejercicios"}

Acerca de Funciones

Muchos scripts de Bash están escritos en un estilo estrictamente imperativo: ejecutar un comando, luego ejecutar otro comando, y así sucesivamente. A veces necesitas agrupar una secuencia de comandos que conceptualmente realizan un único propósito. Aquí es donde entran en juego las funciones.

Definir una función

Defines una función así:

my_function () {
    COMMANDS
}

El conjunto vacío de paréntesis simplemente indica que estás definiendo una función. No va nada dentro de ellos.

Parámetros de las funciones

Las funciones, una vez definidas, actúan como cualquier otro comando (integrado o no). Como cualquier comando, puedes proporcionar argumentos a tus funciones. Dentro de las funciones, accedes a los argumentos usando los parámetros posicionales, $1, $2, etc. (Recuerda, aprendimos sobre los parámetros posicionales en el concepto Variables.)

Advanced

El parámetro especial $0 no cambia dentro de una función; sigue siendo el nombre del script en ejecución. La función que se está ejecutando actualmente puede acceder a su nombre con la variable $FUNCNAME.

Consulta 3.4.2 Parámetros especiales en el manual.

Variables

Puedes definir variables dentro de una función. Si declaras las variables con el comando local, el scope de la variable se limita a la función actual (y a cualquier función llamada por ella). De lo contrario, la variable se coloca en el scope global.

Las variables locales pueden tener el mismo nombre que una variable global. En ese caso, la variable local oculta a la variable global. Por ejemplo, una variable local declarada en una función oculta una variable global del mismo nombre: las referencias y asignaciones se refieren a la variable local, dejando la variable global sin modificar. Cuando la función termina, la variable global vuelve a ser visible.

x=5

myfunc () {
    local x=100
    echo "in my function, $x == 100"
}

echo "in the global scope, $x == 5"

myfunc

echo "back in the global scope, $x == 5"

Esto produce como salida

in the global scope, 5 == 5
in my function, 100 == 100
back in the global scope, 5 == 5

Dentro de una función, puedes acceder a variables desde el scope del llamador. Eso significa que puedes usar variables globales, así como variables locales que se declararon en el llamador (o en alguna función que llame al llamador).

Advanced

Técnicamente, «global» no es la palabra correcta que se debe usar. Para expandir una variable en una función, Bash recorre la pila de llamadas hacia arriba, hasta el scope global, para encontrar una función donde se haya declarado ese nombre de variable.

Este ejemplo está adaptado de la sección Funciones del shell del manual:

func1() {
    local var='func1 local'
    func2
}

func2() {
    echo "In func2, var = $var"
}

var=global
func1
func2

La salida es:

In func2, var = func1 local
In func2, var = global

De manera similar, asignar un valor a una variable lo asignará en el scope donde fue declarada. Esta «acción a distancia» puede crear código difícil de seguir, ya que no siempre es obvio dónde se asignó un valor a una variable.

Advanced

La pila de llamadas se puede examinar usando la variable de array FUNCNAME.

Valores devueltos

Una función, como cualquier comando, tiene un estado de salida. Por defecto, el estado de una función es el estado de salida del último comando ejecutado.

Puedes usar el comando return para salir de una función con un estado de salida específico.

check_password () {
    if [[ $1 == "secret" ]]; then
        return 0
    else
        return 1
    fi
}

read -sp "Enter your password: " pass

if check_password "$pass"; then
    echo "Correct!"
else
    echo "Wrong password."
fi

Usar return sin argumentos devuelve el estado del último comando ejecutado.

Note

Ten en cuenta que la función check_password se puede simplificar a:

check_password () { [[ $1 == "secret" ]]; }
  1. La construcción condicional [[...]] tiene un estado de salida: 0 para «verdadero», 1 para «falso».
  2. La construcción de agrupación {...} debe tener una nueva línea o un punto y coma antes de la llave de cierre.

Salida de las funciones

El estado de salida de una función es solo un número. ¿Cómo puede una función producir salida?

Tu función puede imprimir en la salida estándar. Usa la conocida sustitución de comandos para capturarla:

d6 () { echo "$(( 1 + RANDOM % 6 ))"; }

die=$( d6 )
echo "You rolled a $die."

Usar tanto la salida como el estado

El estado de salida de una función está disponible para usarlo incluso cuando estás capturando la salida.

roll () {
    local n=$1
    if (( 4 <= n && n <= 20 )); then
        echo "$(( 1 + RANDOM % n ))"  # exit status is 0
    else
        return 1
    fi
}

read -p "How many faces does your die have? " faces
if die=$( roll "$faces" ); then
    echo "You rolled a $die."
else
    echo "I can't roll a die with $faces faces."
fi

Recursión

Las funciones pueden llamarse a sí mismas de forma recursiva. Por defecto, no hay límite para la profundidad de recursión.

Un ejemplo:

fibonacci() {
    local n=$1
    if (( n <= 1 )); then
        echo "1"
    else
        local a=$(fibonacci "$(( n - 1 ))")
        local b=$(fibonacci "$(( n - 2 ))")
        echo "$(( a + b ))"
    fi
}

for i in {1..10}; do fibonacci "$i"; done
# => 1
# => 2
# => 3
# => 5
# => 8
# => 13
# => 21
# => 34
# => 55
# => 89
Advanced

La profundidad de recursión se puede controlar con la variable FUNCNEST.

bash -c '
    recur() {
        echo $1
        recur $(($1 + 1))
    }
    FUNCNEST=5
    recur 1
'
1
2
3
4
5
environment: line 1: recur: maximum function nesting level exceeded (5)
Editar en GitHub El enlace se abre en una nueva ventana o pestaña