要测试变量是否是只读的,有以下丑陋的技巧:
# True if readonly
readonly -p | egrep "declare -[:lower:]+ ${var}="
# False if readonly
temp="$var"; eval $var=x 2>/dev/null && eval $var=\$temp
有更优雅的解决方案吗?
使用子 shell 似乎可行。都带有本地变量和导出变量。
$ foo=123
$ bar=456
$ readonly foo
$ echo $foo $bar
123 456
$ (unset foo 2> /dev/null) || echo "Read only"
Read only
$ (unset bar 2> /dev/null) || echo "Read only"
$
$ echo $foo $bar
123 456 # Still intact :-)
重要的是,即使是子 shell 也可以挽救您的 RW(在本例中为 $bar),使其免于在当前 shell 中被取消设置。
使用 bash 和 ksh 进行测试。
您还可以向变量添加一个空字符串,这仍然保留其值,但比使用子 shell 更快,例如:
foo+= 2>/dev/null || echo "Read only"
捕获为函数,它将是:
is-writable() { eval "$1+=" >2/dev/null; }
在问题中,
readonly
的输出被解析为变量名称。类似的方法(避免使用 eval 或 egrep)是检查 declare -p <VARNAME>
是否包含只读标志(或任何其他与此相关的属性)。
# @usage: is_var [-Aailnrtux] <VARNAME>
is_var(){
local i n f=""; [ "${1:0:1}" == - ] && { f="${1:1}"; n=${#f}; shift; }
[[ "$1" =~ ^[_[:alpha:]][_[:alpha:][:digit:]]*$ ]] || return 1
declare -a v && read -ra v < <( declare -p "$1" 2>/dev/null )
[ ${#v} == 0 ] && return 2
[ "$f" ] || return 0
for ((i=0;i<n;++i)) do [[ "${v[1]}" = *"${f:i:1}"* ]] || return 3; done
}
is_array(){ is_var -a "$1"; return $?; };
is_readonly(){ is_var -r "$1"; return $?; };
# examples
is_var HOME && echo "HOME is $HOME"
is_var "foo bar" || echo baz
is_readonly PPID && echo "$_ is readonly" || echo "$_ can be (un)set"
is_array BASH_ARGC && echo "$_ is an array" || echo "$_ is no array"