Bashのビルトインコマンド “declare” の使い方紹介(その3)

2019-02-04Bash, CentOS, Cygwin, Linux, Ubuntu

以下のエントリの続き。

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

今回は 変数に型以外の情報を付与する機能 について。
他の言語で言う public とか finalキーワード をイメージしてもらえばよい。

別の表現をすると、以下の属性を付与する機能と言える。

  • 変数のスコープ
  • 変数の読み取り専用(書き込み禁止)

declare コマンド以外でも設定できる内容であり、以下のキーワードとも絡めてはなしをしたい。

  • readonly
  • export
  • local

検証環境

$ bash --version
GNU bash, バージョン 5.0.2(1)-release (x86_64-apple-darwin18.2.0)
Copyright (C) 2019 Free Software Foundation, Inc.
ライセンス GPLv3+: GNU GPL バージョン 3 またはそれ以降 <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

declareオプション(変数の利用を制限・開放するもの)

-r オプション

読込専用な変数を宣言。値を代入やunsetをできなくなる。

JavaPHP で言うところの final キーワードです。
変数の宣言時にこちらのオプションを付与すると、宣言時に代入した初期値は後から変更することはできない。

# -iオプションも一緒に付与して整数型の読み取り専用変数とする
$ declare -r -i NUM=50

# 値は正しく格納されている
$ echo "${NUM}"
50

# 代入できない
$ NUM=49
bash: NUM: 読み取り専用の変数です

# unsetで変数を開放もできない
$ unset NUM
bash: unset: NUM: 消去できません: variable は読み取り専用です

# -rオプション付与のタイミングで初期化し忘れた場合は悲惨
$ declare -r STR

# 当然空の状態
$ echo "${STR}"

# 代入できない。無意味な変数となってしまった。
$ STR="hogehoge"
bash: STR: 読み取り専用の変数です

連想配列型配列型 の変数にも -r オプションは適用される?

連想配列 で試してみる。

# -rと-aオプションを付与して、読み取り専用の連想配列となるかを確認
$ declare -r -A MAP=([i]=I [my]=MY [me]=ME)

# 変数を確認
$ declare -p MAP
declare -Ar MAP=([my]="MY" [me]="ME" [i]="I" )

# 要素を確認
$ echo "${MAP[me]}"
ME

# 書き換えてみる
$ MAP=hoge
bash: MAP: 読み取り専用の変数です

# 変わっていない
$ echo "${MAP[me]}"
ME

# 要素だけを書き換えてみる
$ MAP[me]=foo
bash: MAP: 読み取り専用の変数です

配列 でも試してみる。

# -rと-aオプションを付与して、読み取り専用の配列となるかを確認
$ declare -r -a ARRAY=(1 2 3)

# 要素を確認
$ echo "${ARRAY[@]}"
1 2 3

# 書き換えてみる
$ ARRAY=(4 5 6)
bash: ARRAY: 読み取り専用の変数です

# 要素だけを書き換えてみる
$ ARRAY[1]=4
bash: ARRAY: 読み取り専用の変数です

変数の再代入ができないだけではなく、 連想配列や配列に格納されている値も再代入不可能 な模様。
完全にイミュータブルであり、安心して使える変数となっている。

readonlyコマンド

declare コマンドを使わずに変数を読み取り専用として宣言する方法もある。
Bash のビルトインコマンドの readonly コマンドを使う方法。

# -iオプションだけを付与して整数型変数を作成
$ declare -i NUM=50

# 値は正しく格納されている
$ echo "${NUM}"
50

# 再代入できる
$ NUM=35

# 値は変更された
$ echo "${NUM}"
35

# 後から読み取り専用の設定を行う
$ readonly NUM

# 書き換えてみる
$ NUM=20
bash: NUM: 読み取り専用の変数です

# 変わっていない
$ echo "${NUM}"
35

declare -rreadonly のそれぞれのコマンドで定義した変数の定義を、 -p オプションを使って確認してみる。

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

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

どちらも declare -r コマンドを使って読み取り専用として定義された変数 となっていることがわかる。

ただし これは関数の外で変数が宣言された場合 の話。
関数の中で変数が宣言された場合には両者の事情が変わってくる。

※続きは次回。

ひとこと

まだまだ1エントリに割く時間がかかってる。
もっとサクサク情報公開していけたらいいのに。

2019-02-04Bash, CentOS, Cygwin, Linux, Ubuntu