Поиск по сайту:

Углубление функциональных сложностей с помощью сценариев оболочки. Часть VII.


Моя предыдущая статья «Понимание и написание функций в сценариях оболочки», возможно, дала вам базовое представление о том, как писать функции в сценариях оболочки. Теперь пришло время углубиться в функциональные возможности, такие как использование локальных переменных и рекурсии.

Локальные переменные

Что делает переменную локальной? Это зависит от того конкретного блока, где объявлена переменная. Переменная, объявленная как local, будет доступна из того блока кода, где она появляется, т. е. ее область действия является локальной. Чтобы объяснить эту вещь, давайте рассмотрим один пример ниже.

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

При выполнении приведенного выше сценария результат будет таким.

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

Это связано с тем, что функция func еще не была вызвана, пока были выполнены первые 2 оператора echo. После вызова функции func одни и те же 2 оператора echo дают другой результат. Теперь к переменной j, которая была объявлена внутри func, а не локальной, можно было впоследствии получить доступ.

Таким образом, значение для j станет 20. А как насчет локальной переменной i? Поскольку его область действия находилась внутри функции func, к значению 10 нельзя было получить доступ извне. Обратите внимание, что переменная j, обычно объявляемая внутри func, по умолчанию является глобальной.

Теперь вы знакомы с локальными переменными и с тем, как их использовать внутри функциональных блоков. Перейдем к самому интересному разделу функций — рекурсии.

Что такое рекурсия?

Функция, вызывающая сама себя, обычно называется процедурой рекурсии. Или его можно определить как выражение алгоритма с использованием более простой версии того же алгоритма. Рассмотрим пример нахождения факториала числа. Мы знаем, что n!=1 х 2 х 3 х… х (n-1) х n. Таким образом, мы можем записать рекуррентное соотношение как:

n! = (n-1)! x n

Поэтому нам легко рекурсивно вызывать одну и ту же функцию и использовать возвращаемое значение каждого вызова для умножения на предыдущий результат, т.е.

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

Рекурсия с использованием локальных переменных

Здесь мы пытаемся написать скрипт для поиска факториала числа с использованием локальных переменных и рекурсии.

#!/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 — это локальная переменная, используемая для хранения каждого значения n-1 при каждом вызове. Здесь базовое условие проверяет, равно ли число нулю или нет (поскольку 0!=1 и факториал не определен для отрицательных чисел). При достижении этого базового условия он возвращает значение 1 вызывающему объекту. Теперь num=1 и ret=1 x 1.

В этот момент он возвращает 1 вызывающему объекту. Теперь num=2 и ret=2 x 1 и так далее. Наконец, когда num=5, возвращаемое значение будет 24, а конечный результат — ret=5 x 24. Конечный результат 120 передается исходному оператору вызывающего абонента и отображается.

В приведенном выше сценарии есть одна проблема. Как я объяснял в предыдущей статье, функции не могут возвращать большие целые числа. Таким образом, пользователям предстоит найти решение вышеуказанной проблемы.

Вопрос. Можно ли выполнить рекурсию без использования локальных переменных? Ответ: Да.

Рекурсия без локальных переменных

Посмотрите на следующий пример отображения ряда Фибоначчи с помощью рекурсии. Основное рекуррентное соотношение:

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

В приведенном выше скрипте не используются локальные переменные. Надеюсь, вы сможете понять ход выполнения сценария.

Здесь значение 15 представляет количество отображаемых членов ряда Фибоначчи. Заметили ли вы что-нибудь особенное в выполнении приведенного выше сценария? Это занимает некоторое время, не так ли? Рекурсия в скрипте медленнее, чем рекурсия в языках программирования, таких как C.

Этой статьей я планирую завершить функциональную часть сценариев оболочки. Следите за обновлениями с помощью Tecmint, чтобы получать новые статьи о массивах и многом другом…