Bash 数组上的间接

Bash 数组上的间接

是否可以编写没有循环的以下脚本?

IPv4_first=1.1.1.1
IPv4_second=2.2.2.2
IPv4_third=3.3.3.3

IPv4_all=() 

for var in ${!IPv4_@}
do
   IPv4_all+=(${!var})
done

printf "'%s'\n" "${IPv4_all[@]}"

就像是:

IPv4_all=${!${!IPv4_@}}

答案1

这可能是我写过的最丑陋的 Bash 代码,但是......

IPv4_first=1.1.1.1
IPv4_second=2.2.2.2
IPv4_third=3.3.3.3

names=(${!IPv4_@})
eval "IPv4_all=(${names[@]/#/$})"
printf "'%s'\n" "${IPv4_all[@]}"

看,妈,没有循环!

${names[@]/#/$}前置 $通过匹配锚定到每个元素的开头的空字符串,到数组的每个元素的开头。这给出了一个变量取消引用的数组,我们可以在其中展开eval以获取数组初始值设定项内的变量引用。这些需要是两个单独的行,因为您不能同时应用多个参数扩展。

输出是:

'1.1.1.1'
'2.2.2.2'
'3.3.3.3'

正如预期的那样。

可以将该行替换为:

IPv4_all=($(eval "echo ${names[@]/#/$}"))

而不是evalling 数组赋值。我不确定这是否更好。

如果您的变量值可能包含空格或其他 IFS 字符,您可以更改 eval:

eval "IPv4_all=($(printf '"$%s" ' "${names[@]}"))"

这正确地用双引号引用了所有变量。

答案2

你不需要IPv4_all变量:

eval printf "\'%s\'\\\n" $(printf "$%s\n" ${!IPv4_@})

输出:

'1.1.1.1'
'2.2.2.2'
'3.3.3.3'

答案3

我的竞赛条目是关于最丑陋/最复杂的 bash 代码;-):

eval 'declare(){ v=${2%%=*};[[ $v = IPv4_* ]]&&IPv4_all+=("${!v}");};'"$(declare -p)"
unset -f declare

答案4

我认为这对我有用,尽管我承认我可能会错过一些基本点:

IPv4_first=1.1.1.1
IPv4_second=2.2.2.2
IPv4_third=3.3.3.3

IPv4_all=( $(set | sed '/IPv4_.*[=)]/!d;s///') )

printf "'%s'\n" "${IPv4_all[@]}"

输出

'1.1.1.1'
'2.2.2.2'
'3.3.3.3'

这个更好:

eval IPv4_all=( "$(set |
    grep -E '^IPv4_[_[:alnum:]]*=([^(]|$)' |
    sed 's/\([^=]*\).*/${\1+"$\1"} /')"
)

grep只获得与您的目标变量匹配的安全行。sed将它们包围在参数扩展标记中,因此如果它们实际上不是当前的 shell 变量名称,则它们的计算结果为零。

相关内容