5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

bash関数での再帰呼び出しサンプル(多重ループの代用→転じて多重xxx)

Last updated at Posted at 2020-01-08

はじめに

諸々の事情があり、bashで動的な多重ループ処理(←ちょっと何言ってるかわからない)を書かねばならないことに。

$ ./xxx.sh 5

なんてやったら、5回の多重ループを実施する。という要件です。

bashでそんなことできんのかよ
と思ったんですがあっさり実現できました。ので共有します。

本編

仕様

指定桁数分、すべての数値の組み合わせを求め、出力します。
具体的には

$ ./xxx.sh 3

とした場合、3桁の000~999、計1000個の数値をコンソール出力します1

コード

以下参照ください(ご使用は自己責任でお願いします)。

$ cat recursive_loop.sh
# !/bin/bash

SOURCE_CHARS="0123456789"
LENGTH=${#SOURCE_CHARS}

# 結果文字列と最大の深さ(初期値は1)
result_str=""
depth_max=1

# 再帰関数本体
function loop_func () {
    # 明示的にローカル変数を使う
    local _count=${1}
    local _i=0
    local _before=""

    for ((_i=0; _i<${LENGTH}; _i++))
    do
        # 終端に1文字を連結
        _before=${result_str}
        result_str=${result_str}${SOURCE_CHARS:${_i}:1}

        # 深さが最大となったら結果出力
        # _countは0始まりなので、depth_maxから1を引いている
        if [ ${_count} -ge $((${depth_max}-1)) ]; then
            echo ${result_str}
        # 最大でなければ再帰呼び出し
        else
            loop_func $((${_count}+1))
        fi

        # if/elseいずれの場合も文字列は連結前に戻す
        result_str=${_before}
    done
}

# パラメータで深さを受け取る
if [ ${#} -ge 1 ]; then
    if [ ${1} -ge 1 ]; then
        depth_max=${1}
    fi
fi

# 再帰呼び出し開始
loop_func 0

実行結果

$ ./recursive_loop.sh
0
(略)
9
$ ./recursive_loop.sh 2
00
(略)
99
$ ./recursive_loop.sh 3
000
(略)
999
$ ./recursive_test.sh 3 | wc -l
1000

汎用化

多重化するのがループだとごちゃつくので、汎用的に「多重xxx」とするなら以下。

$ cat recursive_xxx.sh
# !/bin/bash

# 最大の深さ(初期値は1)
depth_max=1

# 再帰関数本体
# xxxに応じた処理は暫定でechoにしてある
function xxx_func () {
    # 明示的にローカル変数を使う
    local _count=${1}

    # 深さが最大となったら終了
    # _countは0始まりなので、depth_maxから1を引いている
    if [ ${_count} -ge $((${depth_max}-1)) ]; then
        echo "[${_count}] FINISH (Depth=${depth_max})"
    # 最大でなければ再帰呼び出し
    else
        echo "[${_count}] --->"
        xxx_func $((${_count}+1))
        echo "[${_count}] <---"
    fi
}

# パラメータで深さを受け取る
if [ ${#} -ge 1 ]; then
    if [ ${1} -ge 1 ]; then
        depth_max=${1}
    fi
fi

# 再帰呼び出し開始
xxx_func 0

user@user-VirtualBox:~/zip$ ./recursive_xxx.sh 3
[0] --->
[1] --->
[2] FINISH (Depth=3)
[1] <---
[0] <---

技術?ポイント

  • 関数が書ける
  • その関数でローカル変数が使える

言語仕様的にこれらを満たすため、再帰呼び出しも可能なのでした。

アルゴリズム的には、頭が混乱しそうでしたが何とかなった

おわりに

感想

bashもやればできる!笑

確認環境

  • Ubuntu 18.04 LTS
  1. コメントいただいたように、本仕様であればseqコマンドで簡単に実現できますが、あくまで再帰呼び出しの例ということで

5
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?