Bash: 检查关联数组中是否存在键

5

目标:

我只想检查 USER_PARAMETERS_KEYs[j] 是否存在于 RPM_PARAMETERS_HASH 关联数组中。我有一个数组和一个关联数组,如下所示:

预定义:

declare -a USER_PARAMETERS_KEYS='([0]="userField" [1]="fUserField" [2]="srcIPField" [3]="srcPortField" [4]="dstIPField" [5]="dstPortField" [6]="dateField" [7]="timeField")'

declare -A RPM_PARAMETERS_HASH='([timeField]="Time" [userField]="User-Name" [dstIPField]="" [srcIPField]="Source-IP-Address" [dstPortField]="Target-UDP-Port" [fUserField]="Full-Name" [dateField]="Date" [srcPortField]="Source-UDP-Port" )'

我实现了以下内容:

if [[  ${RPM_PARAMETERS_HASH[${USER_PARAMETERS_KEYS[j]}]} ]] ; then
问题

我的问题是当${USER_PARAMETERS_KEYS[j]}等于dstIPField时,由于在关联数组中其有一个空字符串的值,所以if条件不满足,尽管该键存在。

5个回答

2
使用bash,您可以使用-v选项来使用[[
[[ -v RPM_PARAMETERS_HASH["${USER_PARAMETERS_KEYS[j]}"] ]]

所以我将其更改为 if [[ -v RPM_PARAMETERS_HASH[${USER_PARAMETERS_KEYS[j]}] ]]; then,但 if 条件仍未满足。 - Steve
我无法复现,它可以工作,链接到repl。你所说的“仍然不满意”是什么意思? - KamilCuk
${USER_PARAMETERS_KEYS[j]} 评估为环境变量名称时,操作失败。 - Myridium
2
当然可以 - 报价吧。 - KamilCuk

1
@sailnfool - 感谢您找到这个解决方案。 "-v" 解决方案对我无效。
关于 "+_" - 实际上,"+" 符号是 "operator",如 Bash 参考手册中的 "Shell Parameter Expansion" 所述:
"${parameter:+word} 如果参数为 null 或未设置,则不会替换任何内容,否则将替换为 word 的扩展。"
并且在介绍中:"省略冒号只会对未设置的参数进行测试。"
$ declare -A arr; arr["a"]="x"
$ echo ${arr[a]+_}
_
$ echo ${arr[a]+1}
1
$ echo "|${arr[c]+1}|"
||
$ arr["c"]=''
$ [[ ${arr[c]+1} ]] && echo "ok" || echo "nok"
ok
$ [[ ${arr[c]:+1} ]] && echo "ok" || echo "nok"
nok

1
在此回答并澄清@acan和@sailnfool的答案。我发现需要通过一些示例场景来深入理解他们所描述的方法的细微差别(感谢@sailnfool在您的答案中创建的示例脚本)。无论如何,如果我仅仅回复@sailnfool的帖子并留下评论,我的评论将不会很清晰,所以我在这里进行回答。
澄清@sailnfool的脚本/答案的逻辑/结果:
1.如果定义了一个数组,但是数组中的特定元素(键)从未被定义:两个查询都返回“数组元素不存在”的结果
2.如果数组元素的值先前存在并已取消设置:两个查询都返回“数组元素不存在”的结果
3.如果数组元素(键)的值不为NULL:两个查询都返回“数组元素存在”
4.如果数组元素的值为NULL:第一个查询返回“数组元素存在”
5.如果数组元素的值为NULL:第二个查询返回“数组元素不存在”
我不太确定原始问题是要求推导特定数组元素是否存在(即特定数组元素是否已声明),还是要求推导特定数组元素是否具有值(非null)。
如果意图是确定特定数组元素是否曾经被设置(包括将其设置为NULL),则使用此方法:
[[ ${arr[c]+1} ]] && echo "array key exists" || echo "array key does not exist"

例如:

declare -A arr
arr["c"]=""
[[ ${arr[c]+1} ]] && echo "array key exists" || echo "array key does not exist"

或者

declare -A arr
arr["c"]=''
[[ ${arr[c]+1} ]] && echo "array key exists" || echo "array key does not exist"

如果用户的意图是检测数组元素何时存在并随后被取消设置,或特定数组元素从未被创建,任何两种分支方法都将返回相同的结果。即该元素不存在。因此,总结一下...它们之间唯一的区别在于第一种方法(如上所示的示例)能够在数组元素存在但设置为NULL时进行分支。而第二个分支方法只有在定义了数组元素并且包含非空值时才会返回真实路径(数组元素存在)。
底线是:
您的需求场景1:告诉我何时定义了一个数组元素,并且 = 任何值,包括NULL
使用:第一个分支方法 [[ ${arr[c]+1} ]] && echo "array key exists" || echo "array key does not exist"
您的需求场景2:告诉我何时定义了一个数组元素并且包含非NULL值
使用:任何逻辑分支方法 [[ ${arr[c]+1} ]] && echo "array key exists" || echo "array key does not exist" 或者 [[ ${arr[c]:+1} ]] && echo "array key exists" || echo "array key does not exist"
您的需求场景3:告诉我何时根本没有定义数组元素(即从未定义或已定义并随后取消设置)
使用:任何逻辑分支方法 [[ ${arr[c]+1} ]] && echo "array key exists" || echo "array key does not exist" 或者 [[ ${arr[c]:+1} ]] && echo "array key exists" || echo "array key does not exist"

0
在Linuxhint的文章“关联数组Bash示例”1中,第5个示例显示:
$ if [ ${ArrayName[searchKEY]+_} ]; then echo "Exists"; else echo "Not available"; fi

请注意,“searchKEY”可以是字面值,也可以是扩展为字面值的变量。感谢揭示这个“+ _”操作符作为测试键存在的一种方法的文章作者。我无法从GNU BASH参考手册2中找到这个信息。我相信它与参数扩展有关,但我从未意识到它会显示关联(哈希)数组成员的存在。

这在 BaSH 5.1 中对我不起作用,因为它不能处理关联数组。但是,它可以处理数值索引数组。 - MrPotatoHead

-1

看起来你可以通过分步骤操作来使其工作(首先评估密钥,然后使用-v测试):

declare -a USER_PARAMETERS_KEYS='([0]="userField" [1]="fUserField" [2]="srcIPField" [3]="srcPortField" [4]="dstIPField" [5]="dstPortField" [6]="dateField" [7]="timeField")'
declare -A RPM_PARAMETERS_HASH='([timeField]="Time" [userField]="User-Name" [dstIPField]="" [srcIPField]="Source-IP-Address" [dstPortField]="Target-UDP-Port" [fUserField]="Full-Name" [dateField]="Date" [srcPortField]="Source-UDP-Port" )'

j=4
key=${USER_PARAMETERS_KEYS[j]}
[[ -v RPM_PARAMETERS_HASH[$key] ]] && echo yes # output: yes

$key的值为环境变量名称时,会失败。 - Myridium

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接