Ich denke, Sie fragen dort zwei verschiedene Dinge.
Gibt es eine Möglichkeit, Bash dazu zu bringen, diese Informationen ohne die Schleife auszudrucken?
Ja, aber sie sind nicht so gut wie nur mit der Schleife.
Gibt es eine sauberere Methode, um nur den Teil key = value der Ausgabe abzurufen / auszudrucken?
Ja, die for
Schleife. Es hat den Vorteil, dass keine externen Programme erforderlich sind, es ist unkompliziert und es ist ziemlich einfach, das genaue Ausgabeformat ohne Überraschungen zu steuern.
Jede Lösung, die versucht, die Ausgabe von declare -p
( typeset -p
) zu verarbeiten, muss sich mit a) der Möglichkeit befassen, dass die Variablen selbst Klammern oder Klammern enthalten, b) dem Anführungszeichen, declare -p
das hinzugefügt werden muss, damit die Ausgabe für die Shell gültig ist.
Zum Beispiel b="${a##*(}"
frisst Ihre Erweiterung einige der Werte, wenn ein Schlüssel / Wert eine öffnende Klammer enthält. Dies liegt daran, dass Sie verwendet haben ##
, wodurch das längste Präfix entfernt wird. Gleiches gilt für c="${b%% )*}"
. Selbstverständlich könnten Sie das von Ihnen gedruckte Boilerplate declare
genauer zuordnen, aber es würde Ihnen immer noch schwer fallen, wenn Sie nicht alle Zitate wünschen, die es bietet.
Das sieht nicht sehr schön aus, wenn Sie es nicht brauchen.
$ declare -A array=([abc]="'foobar'" [def]='"foo bar"')
$ declare -p array
declare -A array='([def]="\"foo bar\"" [abc]="'\''foobar'\''" )'
Mit der for
Schleife ist es einfacher, das Ausgabeformat nach Belieben auszuwählen:
# 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\'
Von dort aus ist es auch einfach , das Ausgabeformat anderweitig zu ändern (entfernen Sie die Klammern um den Schlüssel, setzen Sie alle Schlüssel / Wert-Paare in eine einzelne Zeile ...). Wenn Sie ein Angebot für etwas anderes als die Shell selbst benötigen, müssen Sie es dennoch selbst erstellen, aber Sie haben zumindest die Rohdaten, an denen Sie arbeiten können. (Wenn Sie Zeilenumbrüche in den Schlüsseln oder Werten haben, müssen Sie wahrscheinlich etwas zitieren.)
Mit einem aktuellen Bash (4.4, glaube ich) könnte man auch printf "[%s]=%s" "${x@Q}" "${array[$x]@Q}"
statt verwenden printf "%q=%q"
. Es erzeugt ein etwas schöneres zitiertes Format, aber es ist natürlich ein bisschen mehr Arbeit, sich daran zu erinnern, es zu schreiben. (Und es zitiert den Eckfall @
als Array-Schlüssel, der %q
nicht zitiert wird.)
Wenn die for-Schleife zum Schreiben zu müde erscheint, speichern Sie sie an einer beliebigen Stelle (ohne hier zu zitieren):
printarr() { declare -n __p="$1"; for k in "${!__p[@]}"; do printf "%s=%s\n" "$k" "${__p[$k]}" ; done ; }
Und dann benutze einfach das:
$ declare -A a=([a]=123 [b]="foo bar" [c]="(blah)")
$ printarr a
a=123
b=foo bar
c=(blah)
Funktioniert auch mit indizierten Arrays:
$ b=(abba acdc)
$ printarr b
0=abba
1=acdc
printf ...%q...
Variante nicht für die erneute Eingabe in die Shell geeignet ist, wenn das Array einen@
Schlüssel hat, da% q ihn nicht in Anführungszeichen setzt unda=([@]=value)
ein Syntaxfehler vorliegtbash
."${x@Q}"
zitiert das auch, da es alle Zeichenketten zitiert (und schöner aussieht). hat einen Hinweis dazu hinzugefügt.zsh
die Variablenerweiterungsflags (die um Jahrzehnte älter sind als Bash und mit denen Sie den Anführungsstil auswählen können: $ {(q) var}, $ {(qq) var} ...) für ein besseres Design. bash hat das gleiche Problem wie mksh, da der leere String nicht in Anführungszeichen gesetzt wird (hier kein Problem, da bash ohnehin keine leeren Schlüssel unterstützt). Auch bei der Verwendung unter Angabe Arten andere als Apostroph (${var@Q}
resorts$'...'
für einige Werte) ist es wichtig , dass der Code REINPUT in der gleichen Örtlichkeit abweichen.x=; echo "${x@Q}"
gibt''
,unset x; echo "${x@Q}"
gibt nichts.) Bashs@Q
scheint$'\n'
eine wörtliche Newline vorzuziehen, was in manchen Situationen tatsächlich gut sein kann (aber ich kann nicht sagen, was andere bevorzugen). Natürlich wäre es nicht schlecht, eine Wahl zu haben.$'...'
Syntax ist ein potenzielles Problem bei bestimmtenLC_ALL=zh_HK.big5hkscs bash -c 'a=$'\''\n\u3b1'\''; printf "%s\n" "${a@Q}"'
Ausgaben$'\n<0xa3><0x5c>'
und0x5c
nur ein Backslash. Wenn dieses Zitat in einem anderen Gebietsschema interpretiert wird, tritt ein Problem auf.2 Gabel
Vielleicht das:
3 Gabeln
oder dieses:
Keine Gabel
zu vergleichen mit
Ausführungszeitvergleich
Da die letzte Syntax keine Verzweigung verwendet, könnten sie schneller sein:
Aber diese Bestätigung bleibt nicht wahr, wenn das Array groß wird; Wenn das Reduzieren von Gabeln bei kleinen Prozessen effizient ist, ist der Einsatz dedizierter Werkzeuge bei größeren Prozessen effizienter.
Anmerkung
Da beide ( gegabelten ) Lösungen die Ausrichtung verwenden , funktioniert keine von ihnen, wenn eine Variable eine neue Zeile enthält . In diesem Fall ist der einzige Weg eine
for
Schleife.quelle
for
. Welches ist eine Schande, wirklich.pr
ist die Syntaxverwendung kürzer ... Ich bin mir nicht sicher, ob diepr
Syntax auch bei großen Arrays langsamer bleibt!${!array[@]}
und${array[@]}
erst, damit das funktioniert.paste
ist länger als diefor
Schleife in der Frage in einer Zeilefor i in "${!array[@]}"; do echo "$i=${array[$i]}" ; done
, erfordert jedoch zwei Subshells und ein externes Programm. Wie ist das ordentlicher? Die Lösung mitpr
unterbricht auch, wenn es viele Elemente gibt, da sie versucht, die Ausgabe zu paginieren. Sie müssten so etwas verwenden,| pr -2t -l"${#array[@]}"
das im Vergleich zur einfachen Schleife immer schwerer zu merken ist und das wiederum länger ist als es.bash
,cmd1 | cmd2
Mittel 2 Gabeln, auch wenn cmd1 oder cmd2 oder beide builtin.Wenn Sie nach einer Shell mit besserer Unterstützung für assoziative Arrays suchen, versuchen Sie es
zsh
.In
zsh
(wo assoziative Arrays im Jahr 1998 hinzugefügt wurden, verglichen mit 1993 für ksh93 und 2009 für bash)$var
oder${(v)var}
erweitert auf die (nicht leeren) Werte des Hash${(k)var}
zu den (nicht leeren) Schlüsseln (in derselben Reihenfolge), und${(kv)var}
sowohl auf Schlüssel als auch auf Werte.Um die leeren Werte wie bei Arrays beizubehalten, müssen Sie das
@
Flag in Anführungszeichen setzen und verwenden .Um die Schlüssel und Werte auszudrucken, ist es nur eine Frage von
Um einen möglicherweise leeren Hash zu berücksichtigen, sollten Sie Folgendes tun:
Beachten Sie auch, dass zsh eine viel sinnvollere und nützlichere Array-Definitionssyntax verwendet als
ksh93
's (kopiert vonbash
):Dies erleichtert das Kopieren oder Zusammenführen von assoziativen Arrays erheblich:
(Sie können einen Hash ohne eine Schleife nicht einfach mit kopieren
bash
, und beachten Sie, dassbash
derzeit keine leeren Schlüssel oder Schlüssel / Werte mit NUL-Bytes unterstützt werden).Siehe auch
zsh
Funktionen zum Komprimieren von Arrays, die Sie normalerweise für assoziative Arrays benötigen:quelle
Da Schriftsatz macht was Sie wollen, warum nicht einfach seine Ausgabe bearbeiten?
gibt
Wo
Ausführlich, aber es ist ziemlich einfach zu verstehen, wie die Formatierung funktioniert: Führen Sie einfach die Pipeline mit immer mehr sed- und tr- Befehlen aus. Ändern Sie sie, um hübschen Druckgeschmack zu entsprechen.
quelle
sed
s undtr
s ist nicht viel einfacher als einefor
Schleife mitprintf
.tr
Zeichen für Zeichen übersetzt werden und dass es nicht mit Zeichenfolgen übereinstimmt?tr "]=" " ="
Ändert "]" zu einem Leerzeichen und=
zu einem=
, unabhängig von der Position. Sie könnten also wahrscheinlich alle dreitr
zu einem kombinieren .Eine weitere Option besteht darin, alle Variablen aufzulisten und nach der gewünschten zu suchen.
set | grep -e '^aa='
Ich benutze dies zum Debuggen. Ich bezweifle, dass es sehr performant ist, da es alle Variablen auflistet.
Wenn Sie dies oft machen würden, könnten Sie es zu einer Funktion wie der folgenden machen:
aap() { set | grep -e "^$1="; }
Leider, wenn wir die Leistung mit der Zeit überprüfen:
$ time aap aa aa=([0]="abc") . real 0m0.014s user 0m0.003s sys 0m0.006s
Wenn Sie dies sehr oft tun würden, würden Sie @ F.Hauris NO FORKS-Version wünschen, weil sie so viel schneller ist.
quelle