ウェブサイト検索

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


私の以前の記事「シェルスクリプトにおける関数の理解と記述」は、シェルスクリプト内で関数を書く方法についての基本的なアイデアを提供したかもしれません。今、ローカル変数の使用や再帰のような機能的な特徴についてさらに深く掘り下げる時です。

ローカル変数

変数をローカルにするものは何ですか?それは変数が宣言されている特定のブロックによります。ローカルとして宣言された変数は、出現するコードのブロックからアクセス可能であり、つまりそのスコープはローカルです。このことを説明するために、以下の例を見てみましょう。

#!/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 文 は異なる結果を生成します。今、func 内で宣言され、ローカルではない変数 j に、その後アクセスできるようになります。

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

さて、ローカル変数とそれらを関数ブロック内でどのように使用するかに慣れました。関数の中で最も興味深いセクションである再帰に進みましょう。

再帰とは何ですか?

自己を呼び出す関数は一般に再帰処理と呼ばれます。また、それは同じアルゴリズムのより単純なバージョンを使用してアルゴリズムを表現することとして定義できます。数の階乗を求める例を考えてみましょう。私たちは次のことを知っています:n!=1 x 2 x 3 x … x (n-1) x 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 が初期の呼び出し元に渡されて表示されます。

上記のスクリプトには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のようなプログラミング言語での再帰よりも遅いです。

この記事では、シェルスクリプトにおける関数の部分を締めくくろうと思います。次回はarraysやその他のトピックに関する記事をお楽しみにするために、Tecmintをチェックしてください…

関連記事: