Einfach eine Zeile Trick für Dumping Array
Ich habe einen Wert mit Leerzeichen hinzugefügt:
foo=([12]="bar" [42]="foo bar baz" [35]="baz")
Für einen schnellen Dump von bash Arrays oder assoziative Anordnungen Ich benutze
Dieser einzeilige Befehl:
paste <(printf "%s\n" "${!foo[@]}") <(printf "%s\n" "${foo[@]}")
Wird gerendert:
12 bar
35 baz
42 foo bar baz
Erläutert
printf "%s\n" "${!foo[@]}"
druckt alle Tasten getrennt durch ein Zeilenumbruch ,
printf "%s\n" "${foo[@]}"
druckt alle Werte getrennt durch ein Zeilenumbruch ,
paste <(cmd1) <(cmd2)
fügt die Ausgabe von cmd1
y cmd2
Zeile für Zeile.
Mahnungen
Dies könnte folgendermaßen eingestellt werden -d
Schalter:
paste -d : <(printf "%s\n" "${!foo[@]}") <(printf "%s\n" "${foo[@]}")
12:bar
35:baz
42:foo bar baz
oder sogar:
paste -d = <(printf "foo[%s]\n" "${!foo[@]}") <(printf "'%s'\n" "${foo[@]}")
foo[12]='bar'
foo[35]='baz'
foo[42]='foo bar baz'
Assoziatives Array funktioniert genauso:
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"
Problem mit Zeilenumbrüche oder Sonderzeichen
Leider gibt es mindestens eine Bedingung, unter der dies nicht mehr funktioniert: wenn die Variable einen Zeilenumbruch enthält:
foo[17]=$'There is one\nnewline'
Befehl paste
wird zeilenweise zusammengeführt, was zu einer falschen Ausgabe führt:
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'
Für diese Arbeit könnten Sie Folgendes verwenden %q
代わりに %s
in zweiter Linie printf
Befehl (und Whipe-Zitat):
paste -d = <(printf "foo[%s]\n" "${!foo[@]}") <(printf "%q\n" "${foo[@]}")
Wird perfekt gemacht ( und wiederverwendbar! ):
foo[12]=bar
foo[17]=$'There is one\nnewline'
foo[35]=baz
foo[42]=foo\ bar\ baz
Von man bash
:
%q causes printf to output the corresponding argument in a
format that can be reused as shell input.
Oder durch Verwendung einer Funktion:
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
}
Dann jetzt:
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!
Über die Ausgabe im UTF-8-Format
Von UTF-8 Zeichenkettenlänge und fügte hinzu:
strU8DiffLen() { local chLen=${#1} LANG=C LC_ALL=C;return $((${#1}-chLen));}
Dann
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