あなたはそこに2つの異なることを求めていると思います。
ループなしでこの情報をbashに出力させる方法はありますか?
はい、ただし、ループを使用するほど良くありません。
出力のキー=値部分のみを取得/印刷するよりクリーンな方法はありますか?
はい、for
ループ。外部プログラムを必要とせず、簡単で、驚くことなく正確な出力形式を制御するのがかなり簡単になるという利点があります。
declare -p
(typeset -p
)の出力を処理しようとするソリューションは、a)括弧または角括弧を含む変数自体の可能性、b)declare -p
シェルの出力を有効にするために追加する必要がある引用符を処理する必要があります。
たとえば、b="${a##*(}"
キー/値に開き括弧が含まれている場合、展開は値の一部を消費します。これは##
、最長のプレフィックスを削除するを使用したためです。同じですc="${b%% )*}"
。もちろん、declare
より正確に印刷されたボイラープレートと一致させることもできますが、引用をすべてしたくない場合は、まだ苦労します。
あなたがそれを必要としない限り、これはあまり良く見えません。
$ declare -A array=([abc]="'foobar'" [def]='"foo bar"')
$ declare -p array
declare -A array='([def]="\"foo bar\"" [abc]="'\''foobar'\''" )'
でfor
ループ、それはあなたが好きなように出力形式を選択する方が簡単です:
# without quoting
$ for x in "${!array[@]}"; do printf "[%s]=%s\n" "$x" "${array[$x]}" ; done
[def]="foo bar"
[abc]='foobar'
# with quoting
$ for x in "${!array[@]}"; do printf "[%q]=%q\n" "$x" "${array[$x]}" ; done
[def]=\"foo\ bar\"
[abc]=\'foobar\'
そこから、出力形式を変更することも簡単です(キーを囲む括弧を削除し、すべてのキー/値のペアを1行に配置します...)。シェル自体以外のものを引用する必要がある場合でも、それを自分で行う必要がありますが、少なくとも作業する生データはあります。(キーまたは値に改行がある場合、おそらく引用符が必要になります。)
現在のBash(4.4、私は思う)では、のprintf "[%s]=%s" "${x@Q}" "${array[$x]@Q}"
代わりに使用することもできますprintf "%q=%q"
。引用符で囲まれた形式の方がやや優れていますが、作成するのを忘れないでください。(そして@
、それ%q
は引用符ではない配列キーとしてのコーナーケースを引用します。)
forループが疲れすぎて記述できない場合は、どこかに関数を保存します(ここでは引用しません)。
printarr() { declare -n __p="$1"; for k in "${!__p[@]}"; do printf "%s=%s\n" "$k" "${__p[$k]}" ; done ; }
そしてそれを使うだけです:
$ declare -A a=([a]=123 [b]="foo bar" [c]="(blah)")
$ printarr a
a=123
b=foo bar
c=(blah)
インデックス付き配列でも動作します:
$ b=(abba acdc)
$ printarr b
0=abba
1=acdc
printf ...%q...
配列に@
キーがあり、%qで引用されておらずa=([@]=value)
、の構文エラーである場合、バリアントの出力はシェルへの再入力には適していませんbash
。