是否可以编写没有循环的以下脚本?
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[@]/#/$}"))
而不是eval
ling 数组赋值。我不确定这是否更好。
如果您的变量值可能包含空格或其他 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 变量名称,则它们的计算结果为零。