Aprofundir en les complexitats de les funcions amb els scripts de Shell - Part VII


El meu article anterior sobre \Comprensió i escriptura de funcions als scripts d'intèrpret d'ordres podria haver-vos donat una idea bàsica sobre com escriure funcions sota scripts d'intèrpret d'ordres. Ara és el moment d'aprofundir en les característiques funcionals com l'ús de variables locals i la recursivitat.

Què fa que una variable sigui local? Depèn del bloc en particular on es declara la variable. Una variable declarada com a local serà accessible des del bloc de codi on apareix, és a dir, el seu abast és local. Per tal d'explicar això, mirem un exemple a continuació.

#!/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

En executar l'script anterior, la sortida serà.

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

Això es deu al fet que la funció func encara no s'ha cridat mentre s'executaven les 2 primeres sentències d'eco. Després de cridar la funció func, les mateixes 2 declaracions d'eco produeixen un resultat diferent. Ara es podia accedir després a la variable j, que es va declarar dins de func i no local.

Així, el valor de j passa a ser 20. Què passa amb la variable local i? Com que el seu abast estava dins de la funció func, no s'ha pogut accedir al valor 10 des de fora. Tingueu en compte que la variable j que normalment es declara dins de func és global per defecte.

Ara esteu familiaritzat amb les variables locals i com utilitzar-les dins dels blocs de funció. Passem a la secció més interessant de funcions, la recursivitat.

Una funció que es crida a si mateixa s'anomena generalment procediment de recursivitat. O es pot definir com l'expressió d'un algorisme utilitzant una versió més senzilla d'aquest mateix algorisme. Considereu l'exemple de trobar el factorial d'un nombre. Sabem que n! = 1 x 2 x 3 x … x (n-1) x n. Així, podem escriure una relació de recurrència com:

n! = (n-1)! x n

Per tant, ens resulta fàcil cridar recursivament a la mateixa funció i utilitzar el valor de retorn de cada trucada per multiplicar-lo amb el resultat anterior, és a dir.

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

Aquí intentem escriure un script per trobar el factorial d'un nombre utilitzant variables locals i recursivitat.

#!/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 és una variable local que s'utilitza per emmagatzemar cada valor n-1 a cada trucada. Aquí la condició base comprova si el nombre és igual a zero o no (ja que 0! = 1 i el factorial no està definit per als nombres negatius). En arribar a aquesta condició base, retorna el valor 1 a la persona que truca. Ara num = 1 i ret = 1 x 1.

En aquest instant torna l'1 a la persona que truca. Ara num = 2 i ret = 2 x 1 i així successivament. Finalment, quan num = 5 el valor de retorn serà 24 i el resultat final serà ret = 5 x 24. El resultat final 120 es passa a la declaració inicial de la persona que truca i es mostra.

Hi ha un problema a l'script anterior. Com he explicat a l'article anterior, les funcions no poden retornar nombres enters grans. Per tant, els usuaris han de trobar una solució per al problema anterior.

P. Podem realitzar recursivitat sense utilitzar variables locals? La resposta és sí.

Mireu l'exemple següent per mostrar la sèrie de Fibonacci amb recursivitat. La relació bàsica de recurrència és:

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

No s'utilitzen variables locals a l'script anterior. Espero que pugueu entendre el flux de l'script durant l'execució.

Aquí el valor 15 representa el nombre de termes de la sèrie de Fibonacci que es mostraran. Heu notat alguna cosa especial pel que fa a l'execució de l'script anterior. Porta una estona, no? La recursió en un script és més lenta que la recursivitat en llenguatges de programació com C.

Amb aquest article, tinc la intenció de concloure la part de funcions de l'script d'intèrpret d'ordres. Estigueu al dia amb Tecmint per tenir els propers articles sobre matrius i molt més...