Búsqueda de sitios web

Profundizando en las complejidades de funciones con Shell Scripting - Parte VII


Mi artículo anterior sobre “Comprensión y escritura de funciones en scripts de Shell” podría haberle dado una idea básica sobre cómo escribir funciones en scripts de Shell. Ahora es el momento de profundizar en características funcionales como el uso de variables locales y la recursividad.

Variables locales

¿Qué hace que una variable sea local? Depende de ese bloque en particular donde se declara la variable. Se podrá acceder a una variable declarada como local desde el bloque de código donde aparece, es decir, su alcance es local. Para explicar esto, veamos un ejemplo a continuación.

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

Al ejecutar el script anterior, el resultado será.

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

Esto se debe a que la función func aún no se ha llamado mientras se ejecutaban las primeras 2 declaraciones de eco. Después de llamar a la función func, las mismas 2 declaraciones de eco producen un resultado diferente. Ahora se puede acceder posteriormente a la variable j, que fue declarada dentro de func y no local.

Por lo tanto, el valor de j se convierte en 20. ¿Qué pasa con la variable local i? Dado que su alcance estaba dentro de la función func, no se podía acceder al valor 10 desde afuera. Tenga en cuenta que la variable j normalmente declarada dentro de func es global de forma predeterminada.

Ahora está familiarizado con las variables locales y cómo usarlas dentro de los bloques de funciones. Pasemos a la sección más interesante de funciones, la recursividad.

¿Qué es la recursividad?

Una función que se llama a sí misma generalmente se denomina procedimiento de recursividad. O puede definirse como la expresión de un algoritmo utilizando una versión más simple de ese mismo algoritmo. Considere el ejemplo de encontrar el factorial de un número. ¡Sabemos que n!=1 x 2 x 3 x … x (n-1) x n. Por tanto, podemos escribir una relación de recurrencia como:

n! = (n-1)! x n

Entonces es fácil para nosotros llamar recursivamente a la misma función y usar el valor de retorno de cada llamada para multiplicar por el resultado anterior, es decir

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

Recursión usando variables locales

Aquí intentamos escribir un script para encontrar el factorial de un número usando variables locales y recursividad.

#!/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 es una variable local que se utiliza para almacenar cada valor n-1 en cada llamada. Aquí la condición base verifica si el número es igual a cero o no (ya que 0!=1 y el factorial no está definido para números negativos). Al llegar a esta condición base, devuelve el valor 1 a su llamador. Ahora num=1 y ret=1 x 1.

En este instante devuelve 1 a su llamador. Ahora num=2 y ret=2 x 1 y así sucesivamente. Finalmente, cuando num=5 el valor de retorno será 24 y el resultado final será ret=5 x 24. El resultado final 120 se transmite a la declaración inicial de la persona que llama y se muestra.

Hay un problema en el script anterior. Como expliqué en el artículo anterior, las funciones no pueden devolver números enteros grandes. Por lo tanto, queda en manos de los usuarios encontrar una solución para el problema anterior.

P. ¿Podemos realizar recursividad sin utilizar variables locales? La respuesta es.

Recursividad sin variables locales

Mire el siguiente ejemplo para mostrar la serie de Fibonacci usando recursividad. La relación de recurrencia básica es:

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 se utilizan variables locales en el script anterior. Espero que puedas entender el flujo del script durante la ejecución.

Aquí el valor 15 representa el número de términos de la serie de Fibonacci que se mostrarán. ¿Notó algo especial con respecto a la ejecución del script anterior? Lleva un tiempo, ¿no? La recursividad en un script es más lenta que la recursividad en lenguajes de programación como C.

Con este artículo, planeo concluir la parte de funciones en scripts de shell. Manténgase actualizado con Tecmint para conocer los próximos artículos sobre arrays y mucho más...