Funzioni e Sottoprocedure
Chiamare altre procedure
Ogni procedura con permesso di esecuzione è un comando Unix e può essere invocata da ogni altra procedura
Si applicano le normali considerazioni di percorsi e permessi
Le procedure chiamate sono eseguite da sottoshell
Tutte le loro variabili sono locali a loro
Se cambiano l'ambiente la procedura chiamante non lo sente
Per eseguire la procedura proc nella shell corrente:
. proc oppure
source proc
Funzioni
Una funzione è semplicemente una serie di istruzioni raggruppate e identificate da un nome
- Le variabili della funzione sono di default globali
- Non vi è un valore di ritorno
In realtà sono subroutines, non funzioni come concepite da altri linguaggi di programmazione.
Sintassi di definizione:
function funzione {
istruzioni
}
Anche solo:
funzione() {
...
}
Invocate solo menzionandone il nome:
. . .
funzione
. . .
Le funzioni devono essere definite prima di essere invocate
Parametri
- Le funzioni possono ricevere parametri
- I parametri attuali sono semplici argomenti dell'invocazione della funzione
- I parametri formali sono
$1 $2
ecc.
Ritorno
- La funzione ritorna dopo la
}
- Può tornare prima col comando
return
- Può settare uno stato di ritorno con
return num
Convenzioni come con le procedure:
0
- successo>0
- fallimento
Il chiamante può testare $?
Esempio.
(funz1.sh)
#! /bin/bash
error(){
echo "$1" >&2
echo "$0: usage: $0 num" >&2
exit $2
}
# main
(( $# < 1 )) && error "Argomenti mancanti" 3
(( $1 < 100 )) && error "Numero troppo piccolo" 250
echo "$1 e' un bel numero"
Notare che il main:
- non ha nessuna etichetta particolare
- non è una funzione
- è l'ultimo codice del file
- è una buona idea commentare l'inizio del
main
I parametri formali del main sono diversi da quelli delle funzioni
Variabili locali
Variabili locali alla funzione sono dichiarate con la parola chiave local
Si può anche simulare un valore di ritorno
Esempio.
(funz2.sh)
#! /bin/bash
mult() {
local risult=$(($1*$2))
echo "$risult"
}
# main
ris=$(mult 3 5)
echo $ris
Il comando eval
Sintassi:
eval assegnazione
Esegue l'assegnazione due volte,
la seconda col risultato della prima
Esempio.
(eval1.sh)
#! /bin/bash
foo=10 bar=foo
x='$'$bar
echo "Senza eval: $x"
eval y='$'$bar
echo "Con eval: $y"
Uso:
./eval1.sh
Senza eval: $foo
Con eval: 10
Notare che non si può scrivere $$bar
poichè la shell tenterebbe di interpretarli entrambi. Occorre che il primo $
sia nascosto con '$'
.
In presenza di quotes la shell ignora il contenuto, ma al contempo le toglie. Quindi quando valutata la seconda volta, y
ha assegnato il valore $foo
ovvero 10
.
Altro esempio.
(eval2.sh)
#! /bin/bash
$( echo var=5 )
eval $( echo var=5 )
echo $var
a="ls * | sort"
$a
eval $a
Lancio:
./eval2.sh
./eval2.sh: line 2: var=5: command not found
5
ls: cannot access |: No such file or directory
ls: cannot access sort: No such file or directory
eval1.sh eval2.sh ...
eval1.sh
eval2.sh
...
Il comando $( echo var=5 )
esegue echo var=5
che manda ad output la stringa var=5
. Non è più un'assegnazione, è una stringa. Tenta poi di eseguire la stringa "var=5
" e non trova nessun comando di quel nome.
Con eval
invece legge la stringa var=5
come se fosse appena stata digitata da tastiera e la vede come assegnazione.
Con a="ls * | sort"
la variabile a
riceve una stringa. Non si può eseguire una stringa che contiene metacaratteri, deve essere riscandita dalla shell per comprendere e interpretare i metacaratteri. Altrimenti vengono visti come argomenti del comando.
Se fosse stato solo a="ls *"
bastava per l'esecuzione, ma nel nostro caso |
e sort
sono visti come nome file argomenti di ls
.
La parte ls *
è ancora valida e viene eseguita, producendo un listato (orizzontale). I comandi completano anche parzialmente.
Se avessimo scritto a="ls *| sort"
non avrebbe riconosciuto nemmeno il file *|
e avrebbe fallito completamente.
Finalmente eval $a
riscandisce la stringa "ls * | sort"
, la comprende e la esegue, producendo un listato verticale.