所以我知道您可以通过间接扩展来测试常规参数的存在,方法如下:
foo=1
bar=foo
(( ${(P)+bar} )) && print "$bar exists"
我知道您可以通过执行以下操作来测试关联数组中是否存在键:
foo=([abc]=1)
(( ${+foo[abc]} )) && print "abc exists"
但是,我无法弄清楚如何将两者结合起来并通过间接扩展测试关联数组中是否存在键。不使用 eval 可以吗?
我尝试了几种组合,包括以下组合,但没有一个有效:
foo=([abc]=1)
bar=foo
(( ${(P)+bar[abc]} )) && print "$bar has key abc" # Test fails
(( ${(P)+${bar}[abc]} )) && print "$bar has key abc" # Passes for nonexistant keys
(( ${${(P)+bar}[abc]} )) && print "$bar has key abc" # Test fails
(( ${${(P)bar}+[abc]} )) && print "$bar has key abc" # prints "zsh: bad output format specification"
答案1
它已经在这里讨论。为了避免传递值,您必须在另一个参数扩展(${:-word}
即)中使用具有正确格式的字符串,然后通过以下方式扩展 ${(P)+...}
:
(( ${(P)+${:-${bar}[abc]}} )) && print OK || print FAIL
答案2
我不知道使用的方法${+param}
,但你可以使用[[ -v $param ]]
:
foo=([abc]=1)
bar=foo
[[ -v "$bar""[abc]" ]] && print "$bar has key abc"
# or "$bar"[abc] or $bar''[abc] or $bar'[abc]'
# or any other way to suppress $bar[abc] being interpreted as a value in $bar
答案3
我发现构建一个表达式并使用 eval 可以解决问题
typeset -A ARRAY_TEST
ARRAY_TEST[key1]=
ARRAY_TEST[key2]=value2
ARRAY_NAME=ARRAY_TEST
# Note: ${NAME+1} will return 1 if a variable is set, otherwise nothing
# for example, ${ARRAY_TEST[key1]+1} will be 1 and
# but ${ARRAY_TEST[key3]+1} will be nothing
[[ $(eval "echo \${${ARRAY_NAME}[key1]+1}") == 1 ]] && echo has key1 || echo no key1
[[ $(eval "echo \${${ARRAY_NAME}[key2]+1}") == 1 ]] && echo has key2 || echo no key2
[[ $(eval "echo \${${ARRAY_NAME}[key3]+1}") == 1 ]] && echo has key3 || echo no key3
# Outputs:
#
# has key1
# has key2
# no key3
我最终为此创建了一个函数......
function array-has-value() {
local testVariable=$1
local keyValue=$2
[[ $(eval "echo \${${testVariable}[$keyValue]+1}") == 1 ]] && return 0 || return 1
}
以下将产生与上面相同的结果:
array-has-value ARRAY_TEST key1 && echo has key1 || echo no key1
array-has-value ARRAY_TEST key2 && echo has key2 || echo no key2
array-has-value ARRAY_TEST key3 && echo has key3 || echo no key3
答案4
这是我发现效果很好的另一个答案:
typeset -A foo=([abc]=def)
has_key() {
local var="${1}[$2]"
(( ${(P)+${var}} )) && return 0
return 1
}
has_key foo abc && print "foo has abc"
has_key foo def || print "foo doesn't have def"
# Outputs:
# foo has abc
# foo doesn't have def