Penso che ci stai chiedendo due cose diverse lì.
C'è un modo per fare in modo che bash stampi queste informazioni senza il ciclo?
Sì, ma non sono buoni come usare il loop.
Esiste un modo più pulito per ottenere / stampare solo la parte chiave = valore dell'output?
Sì, il for
ciclo. Ha i vantaggi di non richiedere programmi esterni, è semplice e semplifica il controllo del formato di output esatto senza sorprese.
Qualsiasi soluzione che tenti di gestire l'output di declare -p
( typeset -p
) ha a che fare con a) la possibilità che le variabili stesse contengano parentesi o parentesi, b) la quotazione che declare -p
deve aggiungere per rendere l'input valido per l'input della shell.
Ad esempio, l'espansione b="${a##*(}"
mangia alcuni dei valori, se una chiave / valore contiene una parentesi aperta. Questo perché hai usato ##
, che rimuove il prefisso più lungo . Lo stesso per c="${b%% )*}"
. Sebbene tu possa ovviamente abbinare la piastra stampata in modo declare
più preciso, avresti comunque difficoltà se non volessi tutte le quotazioni che fa.
Non sembra molto bello a meno che tu non ne abbia bisogno.
$ declare -A array=([abc]="'foobar'" [def]='"foo bar"')
$ declare -p array
declare -A array='([def]="\"foo bar\"" [abc]="'\''foobar'\''" )'
Con il for
loop, è più facile scegliere il formato di output come preferisci:
# 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\'
Da lì, è anche semplice cambiare il formato di output altrimenti (rimuovere le parentesi attorno alla chiave, mettere tutte le coppie chiave / valore su una sola riga ...). Se hai bisogno di un preventivo per qualcosa di diverso dalla shell stessa, dovrai comunque farlo da solo, ma almeno hai i dati grezzi su cui lavorare. (Se hai nuove righe nelle chiavi o nei valori, probabilmente avrai bisogno di un preventivo.)
Con un Bash attuale (4.4, credo), potresti anche usare printf "[%s]=%s" "${x@Q}" "${array[$x]@Q}"
invece di printf "%q=%q"
. Produce un formato citato un po 'più bello, ma ovviamente è un po' più di lavoro da ricordare di scrivere. (E cita il caso d'angolo di @
come chiave dell'array, che %q
non cita.)
Se il ciclo for sembra troppo stanco per scrivere, salvalo da qualche parte (senza citare qui):
printarr() { declare -n __p="$1"; for k in "${!__p[@]}"; do printf "%s=%s\n" "$k" "${__p[$k]}" ; done ; }
E poi basta usare quello:
$ declare -A a=([a]=123 [b]="foo bar" [c]="(blah)")
$ printarr a
a=123
b=foo bar
c=(blah)
Funziona anche con array indicizzati:
$ b=(abba acdc)
$ printarr b
0=abba
1=acdc
printf ...%q...
variante non è adatto per il reinput alla shell se l'array ha una@
chiave poiché% q non la cita eda=([@]=value)
è un errore di sintassibash
.