Bashシェルスクリプトでは、関数の中に関数がかける

はじめに

GitHub 上のシェルスクリプトを見ていたときに面白そうな機能を見つけたので投稿しておきます。

検証環境

1
2
3
4
5
$ uname -moi
x86_64 x86_64 GNU/Linux

$ bash -version | head -n 1
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)

関数の中に関数がかける

スクリプトを見ながら確認してみましょう。

まずは関数を定義します。

1
2
3
$ func1 () {
  echo "Hello world"
}

定義した関数を呼び出してみます。

1
2
$ func1
Hello world

ここから、 func1 の定義を変更します。 func1 の中で func2 という関数を定義し、さら呼び出してみます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 関数を定義する
$ func1 () {
  # 関数func2を定義する
  func2 () {
    echo "I am sub function."
  }

  echo "Hello world"

  # func2を呼び出す
  func2
}

関数 func1 を実行した結果は以下のようになります。

1
2
3
$ func1
Hello world
I am sub function.

関数の中で関数が定義でき、かつそれを呼び出せることがわかります。

関数の中で定義したサブ関数を関数の外で呼び出したどうなる?

関数 func2 を 関数 func1 の外から呼び出したらどうなるでしょうか?

1
2
$ func2
I am sub function.

普通に実行できました。 それでは関数内で関数を定義するメリットとはなんでしょうか?

関数で囲むことで変数のスコープを調整できる

先程のスクリプトを少し変更します。 関数 func1 の中で変数 x を定義し、各所で参照しています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
$ func1 () {
  declare l x="This is x."
  func2 () {
    echo "func2 : x = ${x}"
  }

  func3 () {
    x=y
  }

  echo "func1 : x = ${x}"

  func2

  func3

  func2
}

実行結果は以下のようになります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ func1
func1 : x = This is x.
func2 : x = This is x.
func2 : x = y

# 何も表示されない
$ echo $x

# 変数xは参照できない
$ func2
func2 : x =

関数 func1 で定義した変数 x は、 func1func2func3 のスコープ内では参照、変更できます。 func1 関数のスコープ外では参照できません。

このように変数のスコープを絞り込みために利用することができそうです。

func3 だけは注意が必要です。直接呼び出した場合、変数 x がグローバルに定義されてしまいます。

1
2
3
4
$ func3

$ echo $x
y

ひとこと

便利そうな便利じゃなさそうな。
サブ関数はメイン関数のスコープ内に押し込めてほしい。