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

2023-02-15Bash,CentOS,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 コマンドを使って、関数の中で定義した変数を外で使えるようにはできない?

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

※続きは次回に。

2023-02-15Bash,CentOS,Linux,Ubuntu