Simple one line trick for dumping array
I've added one value with spaces:
foo=([12]="bar" [42]="foo bar baz" [35]="baz")
For a quick dump of bash arrays or associative arrays I use
This one line command:
paste <(printf "%s\n" "${!foo[@]}") <(printf "%s\n" "${foo[@]}")
Will render:
12  bar
35  baz
42  foo bar baz
Explained
- printf "%s\n" "${!foo[@]}"will print all keys separated by a newline,
- printf "%s\n" "${foo[@]}"will print all values separated by a newline,
- paste <(cmd1) <(cmd2)will merge output of- cmd1and- cmd2line by line.
Tunning
This could be tunned by -d switch:
paste -d : <(printf "%s\n" "${!foo[@]}") <(printf "%s\n" "${foo[@]}")
12:bar
35:baz
42:foo bar baz
or even:
paste -d = <(printf "foo[%s]\n" "${!foo[@]}") <(printf "'%s'\n" "${foo[@]}")
foo[12]='bar'
foo[35]='baz'
foo[42]='foo bar baz'
Associative array will work same:
declare -A bar=([foo]=snoopy [bar]=nice [baz]=cool [foo bar]='Hello world!')
paste -d = <(printf "bar[%s]\n" "${!bar[@]}") <(printf '"%s"\n' "${bar[@]}")
bar[foo bar]="Hello world!"
bar[foo]="snoopy"
bar[bar]="nice"
bar[baz]="cool"
Issue with newlines or special chars
Unfortunely, there is at least one condition making this not work anymore: when variable do contain newline:
foo[17]=$'There is one\nnewline'
Command paste will merge line-by-line, so output will become wrong:
paste -d = <(printf "foo[%s]\n" "${!foo[@]}") <(printf "'%s'\n" "${foo[@]}")
foo[12]='bar'
foo[17]='There is one
foo[35]=newline'
foo[42]='baz'
='foo bar baz'
For this work, you could use %q instead of %s in second printf command (and whipe quoting):
paste -d = <(printf "foo[%s]\n" "${!foo[@]}") <(printf "%q\n" "${foo[@]}")
Will render perfect ( and reusable! ):
foo[12]=bar
foo[17]=$'There is one\nnewline'
foo[35]=baz
foo[42]=foo\ bar\ baz
From man bash:
          %q     causes  printf  to output the corresponding argument in a
                 format that can be reused as shell input.
By using a function:
dumpArray() {
    local -n _ary=$1
    local _idx
    local -i _idlen=0
    for _idx in "${!_ary[@]}"; do
        _idlen=" ${#_idx} >_idlen ? ${#_idx} : _idlen "
    done
    for _idx in "${!_ary[@]}"; do
        printf "%-*s: %s\n" "$_idlen" "$_idx" \
            "${_ary["$_idx"]//$'\n'/$'\n\e['${_idlen}C  }"
    done
}
Then now:
dumpArray foo
12: bar
17: There is one
    newline
35: baz
42: foo bar baz
dumpArray bar
foo    : snoopy
bar    : nice
baz    : cool
foo bar: Hello world!
About UTF-8 format output
From UTF-8 string length, adding:
strU8DiffLen() { local chLen=${#1} LANG=C LC_ALL=C;return $((${#1}-chLen));}
Then
dumpArray() {
    local -n _ary=$1
    local _idx
    local -i _idlen=0
    for _idx in "${!_ary[@]}"; do
        _idlen=" ${#_idx} >_idlen ? ${#_idx} : _idlen "
    done
    for _idx in "${!_ary[@]}"; do
        strU8DiffLen "$_idx"
        printf "%-*s: %s\n" $(($?+$_idlen)) "$_idx" \
            "${_ary["$_idx"]//$'\n'/$'\n\e['${_idlen}C  }"
    done
}
Demo:
foo=([12]="bar" [42]="foo bar baz" [35]="baz")
declare -A bar=([foo]=snoopy [bar]=nice [baz]=cool [foo bar]='Hello world!')
foo[17]=$'There is one\nnewline'
LANG=fr.UTF-8 printf -v bar[déjà]  $'%(%a %d %b\n%Y\n%T)T' -1
dumpArray bar
déjà   : ven 24 déc
         2021
         08:36:05
foo    : snoopy
bar    : nice
baz    : cool
foo bar: Hello world!
dumpArray foo
12: bar
17: There is one
    newline
35: baz
42: foo bar baz