ウェブサイト検索

シェル スクリプトによる関数の複雑さの詳細 – パート VII


前回の記事「シェル スクリプトでの関数の理解と作成」では、シェル スクリプトで関数を作成する方法についての基本的なアイデアが得られたかもしれません。ここで、ローカル変数や再帰の使用などの関数機能をさらに深く掘り下げてみましょう。

ローカル変数

変数がローカルになるのはなぜですか?それは、変数が宣言されている特定のブロックによって異なります。 ローカルとして宣言された変数は、それが表示されるコード ブロックからアクセスできます。つまり、そのスコープはローカルです。これを説明するために、以下で 1 つの例を見てみましょう。

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

これは、最初の 2 つの echo ステートメントが実行されている間、 関数func がまだ呼び出されないためです。関数funcを呼び出した後、同じ2 つの echo ステートメントによって異なる結果が生成されます。これで、ローカルではなく func 内で宣言された変数 j に、後でアクセスできるようになりました。

したがって、 j の値は 20 になります。ローカル変数 i はどうでしょうか?スコープが関数 func 内にあったため、値 10 には外部からアクセスできませんでした。通常、func 内で宣言されている変数 j は、デフォルトでグローバルであることに注意してください。

これで、ローカル変数と、それを関数ブロック内で使用する方法について理解できました。関数の下で最も興味深いセクションである再帰に移りましょう。

再帰とは何ですか?

それ自体を呼び出す関数は、一般に再帰手続きと呼ばれます。または、同じアルゴリズムのより単純なバージョンを使用してアルゴリズムを表現すると定義することもできます。数値の階乗を求める例を考えてみましょう。私たちはそれを知っていますん!=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=2ret=2 x 1 などになります。最後にnum=5 の場合、戻り値は 24 になり、 最終結果はret=5 x 24 になります。最終結果 120 は最初の呼び出し元ステートメントに渡されて表示されます。

上記のスクリプトには問題が 1 つあります。前回の記事で説明したように、関数は大きな整数を返すことができません。したがって、上記の問題の解決策を見つけるのはユーザーに任されています。

Q. ローカル変数を使用せずに再帰を実行できますか?答えははいです。

ローカル変数を使用しない再帰

再帰を使用してフィボナッチ数列を表示する次の例を見てください。基本的な漸化関係は次のとおりです。

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 の最新情報を入手して、アレイなどに関する今後の記事を入手してください…