我想您在问两个不同的问题。
有没有一种方法可以使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\'
从那里,以其他方式更改输出格式也很简单(去掉键周围的括号,将所有键/值对放在一行上...)。如果您需要引用除Shell本身以外的内容,则仍然需要您自己报价,但至少您需要处理原始数据。(如果键或值中包含换行符,则可能需要使用一些引号。)
使用当前的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...
如果数组具有@
键,则您的变量的输出不适合重新输入到Shell,因为%q不引用它,并且a=([@]=value)
是中的语法错误bash
。