Fu

Funzioni in Bash

{one: "1 esercizio", many: "%{count} esercizi", other: "%{count} esercizi"}

Informazioni su Funzioni

Molti script Bash sono scritti in uno stile strettamente imperativo: esegui un comando, poi un altro, e così via. A volte hai bisogno di raggruppare una sequenza di comandi che, concettualmente, svolgono un unico scopo. Ed è qui che entrano in gioco le funzioni.

Definire una funzione

Una funzione si definisce così:

my_function () {
    COMMANDS
}

La coppia vuota di parentesi tonde (()) indica semplicemente che stai definendo una funzione. Dentro non ci va nulla.

Parametri di una funzione

Una volta definite, le funzioni si comportano come qualsiasi altro comando (integrato o no). Come per qualsiasi comando, puoi passare degli argomenti alle funzioni. All'interno di una funzione, accedi agli argomenti tramite i parametri posizionali, $1, $2, ecc. (Ricordi? Abbiamo parlato dei parametri posizionali nel concetto Variabili.)

Advanced

Il parametro speciale $0 non cambia all'interno di una funzione: è sempre il nome dello script in esecuzione. La funzione in esecuzione può accedere al proprio nome con la variabile $FUNCNAME.

Vedi 3.4.2 Parametri speciali nel manuale.

Variabili

Puoi definire delle variabili all'interno di una funzione. Se dichiari le variabili con il comando local, lo scope della variabile è limitato alla funzione corrente (e a tutte le funzioni chiamate da essa). Altrimenti, la variabile finisce nello scope globale.

Una variabile locale può avere lo stesso nome di una variabile globale. In quel caso, la variabile locale «oscura» quella globale. Per esempio, una variabile locale dichiarata in una funzione nasconde una variabile globale con lo stesso nome: i riferimenti e le assegnazioni si riferiscono alla variabile locale, lasciando invariata quella globale. Quando la funzione termina, la variabile globale torna a essere visibile.

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"

Questo produce

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

All'interno di una funzione, puoi accedere alle variabili dello scope del chiamante. Questo significa che puoi usare le variabili globali, ma anche le variabili locali dichiarate nel chiamante (o in qualche funzione che chiama il chiamante).

Advanced

Tecnicamente, «globale» non è la parola giusta da usare. Per espandere una variabile all'interno di una funzione, Bash risale la pila delle chiamate, fino allo scope globale, per trovare una funzione in cui quel nome di variabile è stato dichiarato.

Questo esempio è adattato dalla sezione Funzioni della shell del manuale:

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

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

var=global
func1
func2

L'output è:

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

Allo stesso modo, assegnare un valore a una variabile lo assegna nello scope in cui è stata dichiarata. Questa «azione a distanza» può creare codice difficile da seguire, perché non è sempre ovvio dove è stato assegnato un valore a una variabile.

Advanced

La pila delle chiamate si può esaminare usando la variabile array FUNCNAME.

Valori restituiti

Una funzione, come qualsiasi comando, ha uno stato di uscita. Per impostazione predefinita, lo stato di una funzione è lo stato di uscita dell'ultimo comando eseguito.

Puoi usare il comando return per uscire da una funzione con uno stato di uscita specifico.

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

Usare return senza argomenti restituisce lo stato dell'ultimo comando eseguito.

Note

Nota che la funzione check_password può essere semplificata così:

check_password () { [[ $1 == "secret" ]]; }
  1. Il costrutto condizionale [[...]] ha uno stato di uscita: 0 per «vero», 1 per «falso».
  2. Il costrutto di raggruppamento {...} deve avere una nuova riga o un punto e virgola prima della parentesi graffa di chiusura.

Output di una funzione

Lo stato restituito da una funzione è solo un numero. Come può una funzione produrre output?

La funzione può stampare sullo standard output. Usa la familiare sostituzione di comandi per catturarlo:

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

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

Usare sia l'output sia lo stato

Lo stato di uscita di una funzione è disponibile anche quando stai catturando l'output.

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

Ricorsione

Le funzioni possono chiamare se stesse in modo ricorsivo. Per impostazione predefinita, non c'è alcun limite alla profondità della ricorsione.

Un esempio:

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 profondità della ricorsione si può controllare con la variabile 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)
Modifica tramite GitHub Il collegamento si apre in una nuova finestra o scheda