Vyhledávání na webu

Hlouběji do funkčních složitostí se skriptováním Shell – Část VII


Můj předchozí článek o “Porozumění a zápisu funkcí ve skriptech Shell” vám mohl poskytnout základní představu o tom, jak psát funkce pod skripty Shell. Nyní je čas proniknout hlouběji do funkčních funkcí, jako je použití místních proměnných a rekurze.

Místní proměnné

Co dělá proměnnou místní? Záleží na konkrétním bloku, kde je proměnná deklarována. Proměnná deklarovaná jako místní bude přístupná z toho bloku kódu, kde se vyskytuje, tj. její rozsah je lokální. Abychom to vysvětlili, podívejme se na jeden příklad níže.

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

Po provedení výše uvedeného skriptu bude výstup.

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

Je to proto, že funkce func se ještě nezavolala, když byly provedeny první 2 příkazy echo. Po zavolání funkce func vedou stejné 2 příkazy echo k jinému výsledku. Nyní bylo možné později přistupovat k proměnné j, která byla deklarována uvnitř func a nikoli místní.

Hodnota pro j se tedy stane 20. A co místní proměnná i? Protože její rozsah byl uvnitř funkce func, k hodnotě 10 nebylo možné přistupovat zvenčí. Všimněte si, že proměnná j normálně deklarovaná uvnitř func je ve výchozím nastavení globální.

Nyní jste obeznámeni s lokálními proměnnými a jak je používat uvnitř funkčních bloků. Přejděme k nejzajímavější části funkcí, k rekurzi.

Co je rekurze?

Samotné volání funkce se obecně nazývá procedura rekurze. Nebo to může být definováno jako vyjádření algoritmu pomocí jednodušší verze stejného algoritmu. Zvažte příklad hledání faktoriálu čísla. Víme, žen!=1 x 2 x 3 x … x (n-1) x n. Můžeme tedy napsat rekurentní vztah jako:

n! = (n-1)! x n

Takže je pro nás snadné rekurzivně zavolat stejnou funkci a použít návratovou hodnotu z každého volání k vynásobení předchozím výsledkem, tj.

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

Rekurze pomocí lokálních proměnných

Zde se snažíme napsat skript pro nalezení faktoriálu čísla pomocí lokálních proměnných a rekurze.

#!/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 je místní proměnná, která se používá k uložení každé hodnoty n-1 při každém volání. Zde základní podmínka kontroluje, zda je číslo rovno nule nebo ne (protože 0!=1 a faktoriál není definován pro záporná čísla). Po dosažení této základní podmínky vrátí svému volajícímu hodnotu 1. Nyní num=1 a ret=1 x 1.

V tomto okamžiku vrátí svému volajícímu 1. Nyní num=2 a ret=2 x 1 a tak dále. Nakonec, když num=5, návratová hodnota bude 24 a konečný výsledek je ret=5 x 24. Konečný výsledek 120 je předán do úvodního příkazu volajícího a zobrazí se.

Ve výše uvedeném skriptu je jeden problém. Jak jsem vysvětlil v předchozím článku, funkce nemohou vracet velká celá čísla. Je tedy ponecháno na uživatelích, aby našli řešení výše uvedeného problému.

O. Můžeme provést rekurzi bez použití místních proměnných? Odpověď je Ano.

Rekurze bez lokálních proměnných

Podívejte se na následující příklad pro zobrazení Fibonacciho řady pomocí rekurze. Základní vztah opakování je:

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

Ve výše uvedeném skriptu nejsou použity žádné lokální proměnné. Doufám, že rozumíte toku skriptu během provádění.

Zde hodnota 15 představuje počet výrazů v Fibonacciho řadě, které se mají zobrazit. Všimli jste si něčeho zvláštního ohledně provádění výše uvedeného skriptu? Chvíli to trvá, ne? Rekurze ve skriptu je pomalejší než rekurze v programovacích jazycích jako C.

Tímto článkem plánuji uzavřít část funkcí ve skriptování shellu. Zůstaňte v obraze s Tecmint, abyste měli nadcházející články o polích a mnohem více…