我在wiki.bash-hackers.org
找到了这个例子,但是没有解释
细节,所以我希望也许有人在这里,可以对此有所了解,并解释一下
发生了什么。
我理解isSubset
函数的第一行,因为它正在传递args,并使用间接
引用,将密钥存储到内部数组xkeys
和ykeys
。
第二行是设置参数,但我不明白${@/%/[key]}
正在做什么?
看起来像替换,将%
更改为[key]
,我不知道这里会发生什么。
然后在下一行中它比较了元素数量的数组,但不应该是相反的, 如果第一个数组有更多元素,则返回1,因为它不能成为第二个数组的子集?
最后[[ ${!2+_} && ${!1} == ${!2} ]] || return 1
,非常令人困惑。
isSubset() {
local -a 'xkeys=("${!'"$1"'[@]}")' 'ykeys=("${!'"$2"'[@]}")'
set -- "${@/%/[key]}"
(( ${#xkeys[@]} <= ${#ykeys[@]} )) || return 1
local key
for key in "${xkeys[@]}"; do
[[ ${!2+_} && ${!1} == ${!2} ]] || return 1
done
}
main() {
# "a" is a subset of "b"
local -a 'a=({0..5})' 'b=({0..10})'
isSubset a b
echo $? # true
# "a" contains a key not in "b"
local -a 'a=([5]=5 {6..11})' 'b=({0..10})'
isSubset a b
echo $? # false
# "a" contains an element whose value != the corresponding member of "b"
local -a 'a=([5]=5 6 8 9 10)' 'b=({0..10})'
isSubset a b
echo $? # false
}
main
答案 0 :(得分:2)
第二行:
${@/%/[key]}
%
作为模式的第一个字符表示模式必须在末尾匹配。模式中没有其他内容,因此其含义为&#34;最后用“#key”&#39;&#34;替换空字符串。之后,位置参数如下所示:
1 = a[key]
2 = b[key]
下一行:
但不应该是反向的,如果第一个数组有更多的元素,则返回1,
但它确实如此。请注意,||
运算符已被使用,因此如果条件不符合,它将返回1
。条件是:&#34; x.size&lt; = y.size&#34;,如果&#34; x.size&gt;,它将返回1
y.size&#34;
最后:
[[ ${!2+_} && ${!1} == ${!2} ]] || return 1
说实话,我不知道+_
的用途。至于其余部分,请注意我们处于一个带有key
变量的循环中。我们的位置变量中也有key
,所以:
${!1}
变为
${a[key])
和key
变量获取数组a
中的键值。因此整个测试验证第二个数组中存在给定键的值:
[[ ${!2+_} && ...
并且第一个数组中该键的值与第二个数组中该键的值相同:
... && ${!1} == ${!2} ]]
当您传递数组a
时,第一个条件是必要的,它在索引i
处有空字符串而数组b
没有索引{{1} }}:
i
答案 1 :(得分:1)
${@/%/[key]}
的解释是bash手册页的这一部分:
$ {参数/模式/字符串}
扩展模式以生成与路径名一样的模式 扩张。参数被扩展并且最长匹配 对其值的替换用字符串替换。如果是Ipattern 以/开头,模式的所有匹配都用字符串替换。 通常只替换第一场比赛。如果模式开始 使用#,它必须在扩展值的开头匹配 参数。如果pattern以%开头,则必须在结尾处匹配 参数的扩展值。如果string为null,则匹配 删除模式,并且可以省略/以下模式 特德。如果参数是@或*,则替换操作为 依次应用于每个位置参数,并进行扩展 是结果列表。如果参数是一个数组变量子 使用@或*编写脚本,替换操作适用于 依次是数组的每个成员,而扩展是 结果清单。
特别是中间位置%
。因此,${@/%/[key]}
匹配数组中每个值的字符串结尾,并将[key]
附加到其中。
假设isSubset
isSubset a b
a='([0]="0" [1]="1" [2]="2" [3]="3" [4]="4" [5]="5")'
,b='([0]="0" [1]="1" [2]="2" [3]="3" [4]="4" [5]="5" [6]="6" [7]="7" [8]="8" [9]="9" [10]="10")'
和isSubset
。 isSubset() {
local -a 'xkeys=("${!'"$1"'[@]}")' 'ykeys=("${!'"$2"'[@]}")'
中发生的事情是这样的:
$1
将$2
和 local -a 'xkeys=("${!a[@]}")' 'ykeys=("${!b[@]}")'
插入上一行,我们得到
${!arr[@]}
扩展为(通过 local -a 'xkeys=(0 1 2 3 4 5)' 'ykeys=(0 1 2 3 4 5 6 7 8 9 10)'
数组索引扩展)
xkeys
此时我们现在传入了数组键的ykeys
和 set -- "${@/%/[key]}"
数组。
$@
回想一下,@=(a b)
是 set -- 'a[key]' 'b[key]'
,并且从上面的手册页代码段中我们知道这变为
set --
@=('a[key]' 'b[key]')
然后为我们设置函数位置参数,因此我们有 (( ${#xkeys[@]} <= ${#ykeys[@]} )) || return 1
xkeys
如果ykeys
大于set --
,那么它就不能成为一个子集,所以要纾困。 (这可以在 local key
for key in "${xkeys[@]}"; do
行之前完成,而且我想象的效率会略高一些,但除了最热的循环外,其他任何内容都不太重要。)
xkeys
循环遍历key
中的每个键(值为 [[ ${!2+_} && ${!1} == ${!2} ]] || return 1
)。 (注意这里的变量名称,这是至关重要的。)[1]
[[ ${b[key]+_} && ${a[key]} == ${b[key]} ]] || return 1
更多间接,这次是关于位置参数。以上扩展到
${b[key]+_}
如果b[key]
有值,则 ${!2}
扩展为_,否则为空字符串。 (我不确定为什么这会使用替代值扩展而不仅仅使用set -u
而烦恼,但可能有一个原因。面对[[
它可能是安全的,或者可能是安全的反对[
解释生成的字符串,虽然我不认为它会这样做,但b[key]
会有。)因此,此测试在${a[key]} == ${b[key]}
具有值时传递,并在其发生时失败不
[]
测试两个数组中该索引中的值是否相同,并且当任一部分失败时,整个表达式从函数返回失败。
a[key]
索引进行变量扩展,因此位置参数1中的a
不是寻找&#34;关键&#34;数组a[$key]
中的索引,而是 done
}
。
{{1}}
我希望一切都有道理。 (我希望我没事。=)