Я думаю, что вы спрашиваете две разные вещи там.
Есть ли способ заставить bash распечатать эту информацию без цикла?
Да, но они не так хороши, как просто использование цикла.
Есть ли более чистый способ получить / напечатать только часть ключа = значение вывода?
Да, for
петля. Он имеет преимущества, заключающиеся в том, что ему не требуются внешние программы, он прост и позволяет довольно просто контролировать точный формат вывода без неожиданностей.
Любое решение, которое пытается обработать вывод declare -p
( typeset -p
), должно иметь дело с а) возможностью того, что сами переменные содержат скобки или скобки, б) кавычки, которые 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\'
Оттуда также просто изменить формат вывода (удалите скобки вокруг ключа, поместите все пары ключ / значение в одну строку ...). Если вам нужно цитировать что-то, кроме самой оболочки, вам все равно придется делать это самостоятельно, но, по крайней мере, у вас есть необработанные данные для работы. (Если у вас есть новые строки в ключах или значениях, вам, вероятно, понадобятся некоторые цитаты.)
С текущей версией 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
.