シェルオプション assoc_expand_once
を有効にすると、一部の場所で連想配列の添字を 1 回のみ展開するようになります。
Bash バージョン 5.2 以降、一部の場所で 1 回のみ展開するようになりましたが、シェルオプション assoc_expand_once
の挙動と異なります。
※シェルオプション assoc_expand_once
は Bash バージョン 5.2 以降でも影響があります。
展開については以下を参照。
参考「3.5 Shell Expansions - Bash Reference Manual」
※本記事ではパラメータ展開の例を記載しますが、コマンド置換等の他の展開も同様の扱いになります。
1. 基本
Bash バージョン 5.2 現在、シェルオプション assoc_expand_once
の影響を受ける場所は以下の通りです:
- 算術式
-
let
コマンド
-
- 組み込みコマンドによる変数代入
-
printf
コマンド -
read
コマンド -
wait
コマンド
-
- 組み込みコマンドによる配列要素の操作
-
unset
コマンド -
test expr
および[ expr ]
の 条件式の演算子-v
の引数
-
※ Bash バージョン 5.2 で影響を受ける場所は、互換モードのバージョン 5.1 以前でも影響があります。
1.1. 算術式
1.1.1. let
コマンド
#
function f() {
local -rAi assoc_array=([x]=23 ['$x']=42)
local -r x='x'
local -i y
let 'y = assoc_array[$x]'
echo "$y"
}
shopt -u assoc_expand_once
f
shopt -s assoc_expand_once
f
#
function g() {
local -Ai assoc_array=()
local -r x='x'
let 'assoc_array[$x] = 23'
echo "${!assoc_array[@]}"
}
shopt -u assoc_expand_once
g
shopt -s assoc_expand_once
g
23
42
x
$x
ちなみに、整数属性が設定された変数に対して代入文を用いて代入する場合は、シェルオプション assoc_expand_once
の影響を受けません。
#
function f() {
local -rAi assoc_array=([x]=23 ['$x']=42)
local -r x='x'
local -ri y='assoc_array[$x]'
echo "$y"
}
unset BASH_COMPAT
shopt -u assoc_expand_once
f
shopt -s assoc_expand_once
f
BASH_COMPAT=5.1
shopt -u assoc_expand_once
f
shopt -s assoc_expand_once
f
BASH_COMPAT=5.0
shopt -u assoc_expand_once
f
shopt -s assoc_expand_once
f
23
23
23
23
23
23
1.2. 組み込みコマンドによる変数代入
1.2.1. printf
コマンド
#
function f() {
local -A assoc_array=()
local -r x='x'
printf -v 'assoc_array[$x]' foo
echo "${!assoc_array[@]}"
}
shopt -u assoc_expand_once
f
shopt -s assoc_expand_once
f
x
$x
1.2.2. read
コマンド
#
function f() {
local -A assoc_array=()
local -r x='x'
read 'assoc_array[$x]' <<< foo
echo "${!assoc_array[@]}"
}
shopt -u assoc_expand_once
f
shopt -s assoc_expand_once
f
x
$x
1.2.3. wait
コマンド
#
function f() {
local -A assoc_array=()
local -r x='x'
: &
wait -p 'assoc_array[$x]' $!
echo "${!assoc_array[@]}"
}
shopt -u assoc_expand_once
f
shopt -s assoc_expand_once
f
x
$x
1.3. 組み込みコマンドによる配列要素の操作
1.3.1. unset
コマンド
#
function f() {
local -A assoc_array=([x]=foo ['$x']=bar)
local -r x='x'
unset 'assoc_array[$x]'
echo "${!assoc_array[@]}"
}
shopt -u assoc_expand_once
f
shopt -s assoc_expand_once
f
$x
x
1.3.2. test expr
および [ expr ]
の 条件式の演算子 -v
の引数
#
function f() {
local -rA assoc_array=([x]=foo)
local -r x='x'
test -v 'assoc_array[$x]' && echo 'OK' || echo 'NG'
[ -v 'assoc_array[$x]' ] && echo 'OK' || echo 'NG'
}
shopt -u assoc_expand_once
f
shopt -s assoc_expand_once
f
OK
OK
NG
NG
2. Bash バージョン 5.1 以前
Bash バージョン 5.1 以前、シェルオプション assoc_expand_once
の影響を受ける場所は以下の通りです:
- 算術式
- 算術式展開
$(( expression ))
- 算術コマンド
(( expression ))
- 算術
for
文for (( expr1 ; expr2 ; expr3 ))
- インデックス配列の添字
- パラメータ展開の部分列
${parameter:offset}
および${parameter:offset:length}
- 条件コマンド
[[ expression ]]
の算術演算子の引数
- 算術式展開
- 組み込みコマンドによる配列要素の操作
- 条件コマンド
[[ expression ]]
の条件式の演算子-v
の引数
- 条件コマンド
※ Bash バージョン 5.2 で影響を受ける場所は、互換モードのバージョン 5.1 以前でも影響があります。
2.1. 算術式
2.1.1. 算術式展開 $(( expression ))
#
function f() {
local -rAi assoc_array=([x]=23 ['$x']=42)
local -r x='x'
local -r expression='assoc_array[$x]'
echo "$(( expression ))"
local -r subscript='$x'
echo "$(( assoc_array[$subscript] ))"
}
BASH_COMPAT=5.1
shopt -u assoc_expand_once
f
shopt -s assoc_expand_once
f
23
23
42
42
2.1.2. 算術コマンド (( expression ))
#
function f() {
local -rAi assoc_array=([x]=1 ['$x']=0)
local -r x='x'
local -r expression='assoc_array[$x]'
(( expression )) && echo 'OK' || echo 'NG'
local -r subscript='$x'
(( assoc_array[$subscript] )) && echo 'OK' || echo 'NG'
}
BASH_COMPAT=5.1
shopt -u assoc_expand_once
f
shopt -s assoc_expand_once
f
OK
OK
NG
NG
2.1.3. 算術 for
文 for (( expr1 ; expr2 ; expr3 ))
#
function f() {
local -rAi assoc_array=([x]=23 ['$x']=42)
local -r x='x'
local -r expression='assoc_array[$x]'
local -i i
for (( i = expression; i < 1 + expression; i++ )); do
echo "$i"
done
unset i
local -r subscript='$x'
local -i i
for (( i = assoc_array[$subscript]; i < 1 + assoc_array[$subscript]; i++ )); do
echo "$i"
done
unset i
}
BASH_COMPAT=5.1
shopt -u assoc_expand_once
f
shopt -s assoc_expand_once
f
23
23
42
42
2.1.4. インデックス配列の添字
#
function f() {
local -a indexed_array=(foo bar)
local -rAi assoc_array=([x]=0 ['$x']=1)
local -r x='x'
local -r expression='assoc_array[$x]'
indexed_array[expression]=baz
echo "${indexed_array[@]}"
local -r subscript='$x'
indexed_array[assoc_array[$subscript]]=baz
echo "${indexed_array[@]}"
}
BASH_COMPAT=5.1
shopt -u assoc_expand_once
f
shopt -s assoc_expand_once
f
#
function g() {
local -a indexed_array=(foo bar)
local -rAi assoc_array=([x]=0 ['$x']=1)
local -r x='x'
local -r expression='assoc_array[$x]'
echo "${indexed_array[expression]}"
local -r subscript='$x'
echo "${indexed_array[assoc_array[$subscript]]}"
}
BASH_COMPAT=5.1
shopt -u assoc_expand_once
g
shopt -s assoc_expand_once
g
baz bar
baz bar
foo baz
foo baz
foo
foo
bar
bar
2.1.5. パラメータ展開の部分列 ${parameter:offset}
および ${parameter:offset:length}
#
function f() {
local -r parameter=foo
local -rAi assoc_array=([x]=0 ['$x']=1)
local -r x='x'
local -r offset='assoc_array[$x]'
echo "${parameter:offset}"
}
BASH_COMPAT=5.1
shopt -u assoc_expand_once
f
shopt -s assoc_expand_once
f
#
function g() {
local -r parameter=foo
local -rAi assoc_array=([x]=3 ['$x']=2)
local -r x='x'
local -r length='assoc_array[$x]'
echo "${parameter:0:length}"
}
BASH_COMPAT=5.1
shopt -u assoc_expand_once
g
shopt -s assoc_expand_once
g
foo
oo
foo
fo
2.1.6. 条件コマンド [[ expression ]]
の算術演算子の引数
条件式の算術演算子 | 算術式の演算子 | 意味 |
---|---|---|
-eq |
== |
等値 |
-ne |
!= |
非等値 |
-lt |
< |
小なり |
-le |
<= |
小なりイコール |
-gt |
> |
大なり |
-ge |
>= |
大なりイコール |
#
function f() {
local -rAi assoc_array=([x]=1 ['$x']=0)
local -r x='x'
[[ 'assoc_array[$x]' -ne 0 ]] && echo 'OK' || echo 'NG'
}
BASH_COMPAT=5.1
shopt -u assoc_expand_once
f
shopt -s assoc_expand_once
f
OK
NG
2.2. 組み込みコマンドによる配列要素の操作
2.2.1. 条件コマンド [[ expression ]]
の条件式の演算子 -v
の引数
#
function f() {
local -rA assoc_array=([x]=foo)
local -r x='x'
[[ -v 'assoc_array[$x]' ]] && echo 'OK' || echo 'NG'
}
BASH_COMPAT=5.1
shopt -u assoc_expand_once
f
shopt -s assoc_expand_once
f
OK
NG
3. 参考
3.1. シェルオプション
参考「4.3.2 The Shopt Builtin - Bash Reference Manual」
シェルオプション assoc_expand_once
が有効の場合、連想配列の添字の多重評価を抑制します:
- 算術式
- 組み込みコマンドによる変数代入
- 組み込みコマンドによる配列の参照先の取得
3.2. NEWS
参考「NEWS - bash.git - bash」(バージョン 5.2)
- bash-5.2
- シェルオプション
assoc_expand_once
が設定されていない場合でも、組み込みコマンドunset
は添字の解析や展開を行わずに引数を配列の添字として扱おうとする - シェルオプション
assoc_expand_once
が設定されている場合、一部の組み込みコマンドは配列添字を解析しないprintf
test
read
wait
- シェルオプション
- bash-5.0
- 連想配列の添字を 1 回だけ展開しようとする新しいシェルオプション
assoc_expand_once
- 連想配列の添字を 1 回だけ展開しようとする新しいシェルオプション
3.3. COMPAT
参考「COMPAT - bash.git - bash」(バージョン 5.2)
以前のバージョンとの互換性:
- Bash-5.2 では、あたかもシェル オプション
assoc_expand_once
が設定されているかのように動作することにより、特定の状況下、特に算術評価における配列添字の二重展開を防止しようとする
互換性レベル:
- バージョン 5.1
- 条件コマンド
[[
の演算子 (例:[[ -v
) の引数として使用されるインデックス配列および連想配列の添字は複数回展開する- Bash-5.2 では、
assoc_expand_once
オプションが有効になっているかのように動作する
- Bash-5.2 では、
- 条件コマンド
3.4. CHANGES
参考「CHANGES - bash.git - bash」(バージョン 5.2)
- bash-5.2-alpha
- シェルオプション
assoc_expand_once
が設定されていない場合でも、組み込みコマンドunset
は添字の解析や展開を行わずに引数を配列の添字として扱おうとする - シェルオプション
assoc_expand_once
が設定されている場合、一部の組み込みコマンドは配列添字を解析しないprintf
test
read
wait
- シェルオプション
- bash-5.1-rc3
- シェルオプション
assoc_expand_once
は条件式の演算子-v
の引数および条件コマンド[[
の評価に影響する
- シェルオプション
- bash-5.0-alpha
- 連想配列の添字を 1 回だけ展開しようとする新しいシェルオプション
assoc_expand_once
- 連想配列の添字を 1 回だけ展開しようとする新しいシェルオプション
3.5. 互換モード
参考「6.12 Shell Compatibility Mode - Bash Reference Manual」
互換性レベル:
- バージョン 5.1
- 算術式内の展開を複数回行う
- 算術コマンド
(( expression ))
- 算術
for
文for (( expr1 ; expr2 ; expr3 ))
- 条件コマンド
[[ expression ]]
の算術演算子の引数 - パラメータ展開の部分列
${parameter:offset}
および${parameter:offset:length}
- 算術式展開
$(( expression ))
- インデックス配列の添字
- 算術コマンド
- 算術式内の展開を複数回行う
3.6. Changelog
3.6.1. バージョン 5.0
参考「changelog\CWRU - bash.git - bash」(バージョン 5.0)
- 2016-12-12
-
arrayfunc.c
-
assoc_expand_once
: 新しい変数
-
-
arrayfunc.h
assoc_expand_once
-
builtins/set.def
-
unset_builtin
:assoc_expand_once
-
-
builtins/shopt.def
-
assoc_expand_once
: 新しいシェルオプション
-
-
expr.c
assoc_expand_once
-
arrayfunc.c
- 2016-12-14
-
expr.c
-
expr_bind_variable
:assoc_expand_once
-
-
expr.c
- 2016-12-15
-
builtins/read.def
-
read_builtin
:assoc_expand_once
-
bind_read_variable
:assoc_expand_once
-
-
builtins/printf.def
-
printf_builtin
:assoc_expand_once
-
bind_printf_variable
:assoc_expand_once
-
-
builtins/read.def
- 2018-01-31
-
doc/{bash.1,bashref.texi}
-
shopt
:assoc_expand_once
-
-
doc/{bash.1,bashref.texi}
- 2018-09-23
-
arrayfunc.c
-
assign_array_element
:assoc_expand_once
-
-
arrayfunc.c
- 2018-09-29
-
arrayfunc.c
-
valid_array_reference
:assoc_expand_once
-
-
arrayfunc.c
- 2018-10-16
-
expr.c
-
expr_skipsubscript
:assoc_expand_once
-
-
expr.c
3.6.2. バージョン 5.1
参考「changelog\CWRU - bash.git - bash」(バージョン 5.1)
- 2018-11-10
-
test.c
-
unary_test
:assoc_expand_once
[[
[
-
-
test.c
3.6.3. バージョン 5.2
参考「changelog\CWRU - bash.git - bash」(バージョン 5.2)
- 2021-05-06
-
execute_cmd.c
-
execute_cond_command
:-v
unary_test
assoc_expand_once
-
-
execute_cmd.c
- 2021-05-07
-
builtins/common.[ch]
-
set_expand_once
:array_expand_once
-
-
execute_cmd.c
-
execute_cond_node
:-v
unary_test
set_expand_once
array_expand_once
-
-
builtins/common.[ch]
- 2021-05-09
-
builtins/shopt.def
-
expand_once_flag
:assoc_expand_once
set_assoc_expand
-
set_assoc_expand
:expand_once_flag
assoc_expand_once
-
-
builtins/common.h
expand_once_flag
-
builtins/shopt.def
- 2021-05-11
-
test.c
-
unary_test
:-v
valid_array_reference
assoc_expand_once
-
-
test.c
- 2021-11-16
-
builtins/common.c
-
set_expand_once
:-v
assoc_expand_once
[[
-
-
builtins/common.c
- 2021-12-29
-
builtins/common.h
-
SET_VFLAGS
:assoc_expand_once
-
vflags
:valid_array_reference
-
bindflags
:assign_array_element
bind_int_variable
-
-
-
builtins/printf.def
-
printf_builtin
:SET_VFLAGS
assoc_expand_once
-
-
builtins/read.def
-
read_builtin
:SET_VFLAGS
assoc_expand_once
-
-
builtins/common.h