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、配列イニシャライザ内で変数参照を取得するために拡張できる変数逆参照配列を提供します。複数のパラメータ拡張を同時に適用できないため、2つの別々の行が必要です。

出力は次のとおりです

'1.1.1.1'
'2.2.2.2'
'3.3.3.3'

予想通り。

この行は次のように置き換えることができます。

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

evalリング配列割り当ての代わりに。これが良いかどうかはわかりません。

変数の値にスペースやその他の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パラメータ拡張マークで囲まれ、実際に現在のシェル変数名ではない場合はゼロと評価されます。

関連情報