bashのshellscriptを書くときに,変数を書き換え不可にして定義をしたいときがよくある.
#!/bin/bash
FILEPATH=$0
...
FILEPATH=another_value
この場合,${FILEPATH}はこのスクリプトファイルへのパスなのだから後で別の値を代入できるようにしたくない.今までこのようなときはreadonlyのbuiltin commandを使って実現していたが,declare -rという定義の方法でも同じことができるらしい.何か違いがあるのかを調べてみた.
結論から言うと,変数のスコープに違いが生じる.declare -rはローカルスコープ, readonlyはグローバルスコープになる.
#!/bin/bash
function func () {
foo=10
local bar=20
declare -r baz=30
readonly qux=40
declare -rg quux=50
}
func
echo ${foo}
echo ${bar}
echo ${baz}
echo ${qux}
echo ${quux}
Output:
$ ./example.sh
10
40
50
foo: 修飾子なし.関数内で定義された変数は関数外でも参照可
bar: local修飾子あり.localで修飾された変数は,定義された関数内とその子の関数内でしか可視でなくなる.
baz: declare -rで修飾された変数は書き換え不可となる.スコープはローカルになる.
qux: readonlyで修飾された変数は書き換え不可となる.スコープはグローバルとなる.
quux: declare -rgで修飾された変数は書き換え不可となる.スコープはグローバルとなる.
readonlyとdeclare -rgは同じと見てよさそう.また,manを読んでいてdeclareの説明のところにtypesetというbuiltin commandがあったが,bashにおいては完全にdeclareと同じものでobsoluteなコマンドらしい.
ちなみに,Mac環境のbashではdeclare -gのオプションは存在していないようだった.
$ cat ex.sh
#!/bin/bash
func () {
declare -gr foo=30
}
func
echo "foo: " ${foo}
$ ./ex.sh
./ex.sh: line 4: declare: -g: invalid option
declare: usage: declare [-afFirtx] [-p] [name[=value] ...]
foo:
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.12.6
BuildVersion: 16G29
$ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-apple-darwin16.3.0)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <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.
元々調査した環境は
CentOS 7.3 (GNU bash, version 4.2.46(1)-release (x86_64-redhat-linux-gnu))
おまけ: localで修飾された変数は孫の関数内でも参照できるのか試したもの
#!/bin/bash
function f () {
local hoge=1000
echo ${hoge}
function g () {
echo ${hoge}
function h () {
echo ${hoge}
}
h
}
g
}
f
Output:
$ ./example.sh
1000
1000
1000
参考
In bash script, what’s the different between declare and a normal variable?