bash 关联数组的异常测试 -v 结果

问题描述 投票:0回答:2

遇到了这个明显的异常现象。测试代码:

(
    set -x
    declare -A a=()
    for i in x "'" '"'
    do
        a[$i]=
        test -v a[$i] && true
    done
    : "${!a[@]}"
)

输出:

+ a=()
+ declare -A a
+ for i in x "'" '"'
+ a[$i]=
+ test -v 'a[x]'
+ true
+ for i in x "'" '"'
+ a[$i]=
+ test -v 'a['\'']'
+ for i in x "'" '"'
+ a[$i]=
+ test -v 'a["]'
+ : \' '"' x

我预计

true
会被执行三次,而不仅仅是一次。似乎
test -v
对于关联数组元素失败,其中索引扩展为包含引号字符的内容。

这是一个 bash 错误,还是只是我需要更明智的期望?

bash conditional-statements associative-array
2个回答
0
投票

似乎是一个错误。

不过我找到了解决方法:

declare -A a=()
for i in x '"a"' a '"a"' ']' '[' '\' "'" '"' y
do
    a[$i]=
    [[ -v 'a[$i]' ]] && echo "true $i"
done

0
投票

好的,猜对了。

这有效:

(
    set -x
    declare -A a=()
    a[x]= a["'"]= a['"']=
    for i in x "'" '"' y
    do
        test -v 'a[$i]' && true
    done
    : "${!a[@]}"
)

输出:

+ a=()
+ declare -A a
+ a[x]=
+ a["'"]=
+ a['"']=
+ for i in x "'" '"' y
+ test -v 'a[$i]'
+ true
+ for i in x "'" '"' y
+ test -v 'a[$i]'
+ true
+ for i in x "'" '"' y
+ test -v 'a[$i]'
+ true
+ for i in x "'" '"' y
+ test -v 'a[$i]'
+ : \' '"' x

现在,唯一失败的

test -v
是数组元素
a[y]
的那个,它确实从未被设置过。

不成文的规则似乎是,提供给

name
test -v name
参数的处理方式与 shell 解析命令时 shell 变量赋值中
=
左侧的任何内容完全相同线。具体来说,在测试结果名称是否具有所指对象之前,将评估任何此类
name
的下标部分内的任何扩展语法。此外,为了使报价删除正确运行,此类扩展必须以这种方式推迟;在
name
作为参数传递给
test
之前,不能允许它们发生。

同样适用于作为参数提供给

unset
的名称。

我在 bash 手册中能找到的最接近这一点的是数组部分中的这一段

当使用带下标的变量名作为变量的参数时 命令,例如 unset,不使用单词扩展语法 如上所述,参数取决于 shell 的文件名 扩张。如果不需要扩展文件名,则该参数应该 被引用。

我觉得这与当前的问题有点无关。我不认为这只是变量扩展:我认为它是完整的 Monty。如果您感觉有点颤抖,请尝试

unset 'a[x$(ls -al >&2)]'
;那里可能潜伏着一类有趣的脚本注入漏洞。

总结:如果您要使用

test -v
来测试关联数组中是否存在某个条目,请将名称用单引号而不是双引号括起来,即使它包含其他变量的扩展也是如此。你想要
test -v 'a[$i]'
,而不是任何像
test -v "a[$i]"
一样扩展的东西。同样适用于
unset

© www.soinside.com 2019 - 2024. All rights reserved.