シェルスクリプトで再帰する

ふと気になって、関数の再帰呼び出しをしらべてみました。OSはHP-UX 11iです。

#!/usr/bin/ksh

typeset -i index

function recursive_function {
    let index=${index}+1
    if [ $index -eq 10 ]; then
        : # ヌルコマンドで関数を抜ける
    else
        echo $index
        recursive_function
    fi
}

echo "start"

recursive_function

echo "end"

exit 0

次にスクリプト自分自身を呼び出してみました。

#!/usr/bin/ksh

typeset -i index

let index=${index}

export index # サブプロセスに引き継ぐため

if [ $index -eq 1 ]; then # 初回だけわざわざ区別
    echo "start"
fi

if [ $index -eq 10 ]; then
    echo "end"
else
    echo $index
    ./recursive_sh.ksh
fi

exit 0

実行結果はどちらも

start
1
2
3
4
5
6
7
8
9
end

です。
シェルスクリプト自身を呼び出す方は、開始と終了のメッセージを出すように書こうとしただけでスパゲッティ気味ですね。ほかに、スクリプト自身を呼び出す方は0以外で初期化しようとすると面倒ですね。
次に何回まで再帰できるかを試してみました(コード中の10を適当に変更)。いろいろ試してみたところ、関数を使った方は128回を越えたところで、エラーになりました。

./recursive_function.ksh[17]: recursive_function: recursion too deep

スクリプト自身を呼び出す方は、実行が関数を使う方よりずっと遅く、かなりの回数でも大丈夫なようで途中でキャンセルしました。

128回の再帰呼び出しで実行時間を比較してみると、予想通りかなりの差がありました。同一プロセスで実行されているかどうかということですよね。

$ time (recursive_function.ksh 1>/dev/null)

real    0m0.01s
user    0m0.01s
sys     0m0.01s
$ time (recursive_sh.ksh 1>/dev/null)

real    0m0.96s
user    0m0.18s
sys     0m0.79s