Ricerca nel sito web

Approfondimento delle complessità delle funzioni con Shell Scripting – Parte VII


Il mio precedente articolo su "Comprendere e scrivere funzioni negli script di shell" potrebbe averti dato un'idea di base su come scrivere funzioni negli script di shell. Ora è il momento di approfondire le caratteristiche funzionali come l'uso di variabili locali e la ricorsione.

Variabili locali

Cosa rende locale una variabile? Dipende da quel particolare blocco in cui è dichiarata la variabile. Una variabile dichiarata come local sarà accessibile da quel blocco di codice in cui appare, ovvero il suo ambito è locale. Per spiegare questa cosa esaminiamo un esempio qui sotto.

#!/bin/bash 

func( ) { 
	local i=10 
	j=20 
	echo "i from func = $i" 
	echo "j from func = $j" 
} 

echo "i outside func = $i" 
echo "j outside func = $j" 

func 

echo "i outside func = $i" 
echo "j outside func = $j" 

exit 0

Eseguendo lo script sopra l'output sarà.

i outside func = 
j outside func = 
i from func = 10 
j from func = 20 
i outside func = 
j outside func = 20

Questo perché la funzione func non è stata ancora chiamata mentre venivano eseguite le prime 2 istruzioni echo. Dopo aver chiamato la funzione func le stesse 2 istruzioni echo producono un risultato diverso. Ora è possibile accedere in seguito alla variabile j, che è stata dichiarata all'interno di func e non locale.

Pertanto il valore per j diventa 20. Che dire della variabile locale i? Poiché il suo ambito era all'interno della funzione func, non era possibile accedere al valore 10 dall'esterno. Nota che la variabile j normalmente dichiarata all'interno di func è globale per impostazione predefinita.

Ora hai familiarità con le variabili locali e come utilizzarle all'interno dei blocchi funzione. Passiamo alla sezione più interessante delle funzioni, la ricorsione.

Cos'è la ricorsione?

Una funzione che richiama se stessa viene generalmente definita procedura di ricorsione. Oppure può essere definito come espressione di un algoritmo utilizzando una versione più semplice dello stesso algoritmo. Consideriamo l'esempio della ricerca del fattoriale di un numero. Sappiamo che n!=1 x 2 x 3 x … x (n-1) x n. Possiamo quindi scrivere una relazione di ricorrenza come:

n! = (n-1)! x n

Quindi è facile per noi chiamare ricorsivamente la stessa funzione e utilizzare il valore restituito da ciascuna chiamata per moltiplicarlo con il risultato precedente, ovvero

5! = 4! x 5
4! = 3! x 4
3! = 2! x 3
2! = 1! x 2
1! = 0! x 1

Ricorsione utilizzando variabili locali

Qui proviamo a scrivere uno script per trovare il fattoriale di un numero utilizzando variabili locali e ricorsione.

#!/bin/bash 

fact( ) { 
	local num=$1 
	if [ $num -eq 0 ]; then 
		ret=1 
	else 
		temp=$((num-1)) 
		fact $temp 
		ret=$((num*$?)) 
	fi 
	return $ret 
} 

fact 5 

echo "Factorial of 5 = $?" 

exit 0

num è una variabile locale utilizzata per memorizzare ciascun valore n-1 su ciascuna chiamata. Qui la condizione di base controlla se il numero è uguale a zero o meno (poiché 0!=1 e il fattoriale non è definito per i numeri negativi). Al raggiungimento di questa condizione di base restituisce il valore 1 al chiamante. Ora num=1 e ret=1 x 1.

In questo istante restituisce 1 al chiamante. Ora num=2 e ret=2 x 1 e così via. Infine, quando num=5 il valore restituito sarà 24 e il risultato finale sarà ret=5 x 24. Il risultato finale 120 viene passato all'istruzione iniziale del chiamante e viene visualizzato.

C'è un problema nello script sopra. Come ho spiegato nell'articolo precedente, le funzioni non possono restituire numeri interi di grandi dimensioni. Quindi spetta agli utenti trovare una soluzione per il problema di cui sopra.

D. Possiamo eseguire la ricorsione senza utilizzare variabili locali? La risposta è.

Ricorsione senza variabili locali

Guarda il seguente esempio per visualizzare la serie di Fibonacci utilizzando la ricorsione. La relazione di ricorrenza di base è:

fib(0) = 0 
fib(1) = 1 
else 
	fib(n) = fib(n-1) + fib(n-2)

Fibonacci series using recursion

#!/bin/bash 

fib( ) { 
	a=$1 
	if [ $a -lt 2 ]; then 
		echo $a 
	else 
		((--a)) 
		b=$(fib $a) 

		((--a)) 
		c=$(fib $a) 

		echo $((b+c)) 
	fi 
} 

for i in $(seq 0 15) 
do 
	out=$(fib $i) 
	echo $out 
done 

exit 0

Nello script precedente non vengono utilizzate variabili locali. Spero che tu possa comprendere il flusso dello script durante l'esecuzione.

Qui il valore 15 rappresenta il numero di termini della serie di Fibonacci da visualizzare. Hai notato qualcosa di speciale riguardo all'esecuzione dello script sopra. Ci vuole un po', vero? La ricorsione in uno script è più lenta di una ricorsione nei linguaggi di programmazione come il C.

Con questo articolo intendo concludere la parte relativa alle funzioni nello scripting di shell. Rimani aggiornato con Tecmint per avere i prossimi articoli sugli array e molto altro ancora...