Bashのビルトインコマンド `declare` の使い方紹介(変数のlocalスコープ)

2019-03-09Bash, CentOS, Cygwin, Linux, Ubuntu

またまた、以下のエントリの続き。

  1. シェルスクリプトサンプルコードでよく見かけるtypesetやdeclareってなに?
  2. Bashのビルトインコマンド “declare” の使い方紹介(その1)
  3. Bashのビルトインコマンド “declare” の使い方紹介(その2)
  4. Bashのビルトインコマンド “declare” の使い方紹介(その3)

※だんだんシリーズみたいになってきました(笑)

今回は 前回 の続きで、Bashにおける変数のスコープ(参照可能な範囲)について。

検証環境

$ bash -version
GNU bash, バージョン 5.0.2(1)-release (x86_64-apple-darwin18.2.0)

declare コマンドで宣言した変数は関数の中だけのいのち

読み取り専用の変数を宣言するためには、declare -p を使っても readonly を使っても違いはなさそうというところまで確認しました。

$ declare -r A=a1
$ readonly B=b1

# `-p` オプションで変数がどのように宣言されたものかを確認できます。
# 変数名を複数指定して、いっぺんに出力することもできます。
$ declare -p A B
declare -r A="a1"
declare -r B="b1"

Bashのビルトインコマンド “declare” の使い方紹介(その3) の終わりでも話したとおり、これは 関数の外部で変数が宣言された場合 のみの話。
関数の内部で宣言された変数の場合には事情が異なります。
関数の内部で宣言された場合の両者の違いを見ていきましょう。

# 関数を作成
$ function f() {
  declare -r C=c1
  readonly D=d1
  echo "f: C=$C D=$D"
}

# 関数の呼び出しを行っていないため、いずれの変数も値は空
$ echo "C=$C D=$D"
C= D=

# 関数を呼び出して、関数内の変数値を出力
$ f
f: C=c1 D=d1

# 関数の内部で代入したDの値は参照可能
$ echo "C=$C D=$D"
C= D=d1

# 変数は見つからない
$ declare -p C
bash: declare: C: 見つかりません

# 変数が見つかる
$ declare -p D
declare -r D="d1"

declare で宣言した変数は、関数の内部でしか参照できません。

local コマンド

declare -rreadonly の関係と同じように、 declare を使わずにローカルスコープの変数を宣言することが可能です。 local というBashのビルトインコマンドを使います。

# 関数を作成
$ function f() {
  declare -r C=c1
  # ローカルスコープとして宣言
  local D=d1
  # 読み取り専用
  readonly D
  echo "f: C=$C D=$D"
}

# 関数の呼び出しを行っていないため、いずれの変数も値は空
$ echo "C=$C D=$D"
C= D=

# 関数を呼び出して、関数内の変数値を出力
$ f
f: C=c1 D=d1

# 関数の内部で代入したDの値は参照可能
$ echo "C=$C D=$D"
C= D=

# 変数は見つからない
$ declare -p C
bash: declare: C: 見つかりません

# 変数は見つからない
$ declare -p D
bash: declare: D: 見つかりません

local コマンドのみを使うことも可能だし、 readonly コマンドのみを使うこともできます。
local コマンドと readonly コマンドを組み合わせて使う場合には、順序が重要です。
readonly => local の順番で呼び出すことはできません。

$ function f() {
  local X=1
  readonly X
  declare -p X

  readonly Y=2
  local Y
  declare -p Y
}

$ f
declare -r X="1"
bash: local: Y: 読み取り専用の変数です
declare -r Y="2"

$ echo "X=$X Y=$Y"
X= Y=2

local コマンドは関数の内でしか使うことはできません。

$ local Z=3
bash: local: 関数の中でのみ使用できます

呼び出し順序やら関数内部でしか使えないやらでややこしいので、 readonly コマンドや local コマンドを覚えるよりも、 declare の使い方を覚えてしまったほうが良いと思います。

declare コマンドを使って、予め関数の外で宣言した変数は関数の中でどう見える?

これは問題なく参照できます。

# 関数の外で宣言
$ declare A=4

# 関数の中で参照
$ function f() {
  echo $A;
}

# ちゃんと出力される
$ f
4

declare コマンドを使って、関数の中で宣言した変数を外で使えるようにはできない?

あまりないケースだとは思うが、これもできます。

※続きは次回に。

2019-03-09Bash, CentOS, Cygwin, Linux, Ubuntu