2016-09-09 3 views
1

Ich versuche, ein assoziatives Array mit der Ausgabe eines Befehls zu füllen. Ich kann es tun, ohne einen Befehl wie:Wie bevölkere ich ein bash-assoziatives Array mit Befehlsausgabe?

$ declare -A x=([first]=foo [second]=bar) 
$ echo "${x[first]}, ${x[second]}" 
foo, bar 

und ich kann ein nicht-assoziatives Array mit Befehlsausgabe als bevölkern:

$ declare y=($(echo 'foo bar')) 
$ echo "${y[0]}, ${y[1]}" 
foo, bar 

aber wenn ich versuche, auf beide oben zu bauen zu erstellen eine Aussage, die ein assoziatives Array von einem Befehl bevölkern, ich die folgende Fehlermeldung erhalten:

$ declare -A z=($(echo '[first]=foo [second]=bar')) 
-bash: z: $(echo '[first]=foo [second]=bar'): must use subscript when assigning associative array 

Warum bin ich die Fehlermeldung bekommen und was ist die richtige Syntax eines assoziativen zu füllen Array mit der Ausgabe eines Befehls? Ich versuche zu vermeiden, eval für the usual reasons zu verwenden, möchte nicht eine temporäre Datei verwenden, und natürlich echo wird nur als ein Beispiel für einen Befehl verwendet, der den fraglichen Effekt erzeugt, der echte Befehl wird komplizierter.

So, basierend auf ein paar der folgenden Antworten, es sieht aus wie es war meine nur zitiert, dass ein Problem war:

$ declare -A z="($(echo '[first]=foo [second]=bar'))" 
$ echo "${z[first]}, ${z[second]}" 
foo, bar 

und mit Leerzeichen in den Indizes und Werte:

$ declare -A z="($(echo '[first field]="foo with space" [second]="space bar"'))" 
$ echo "${z[first field]}, ${z[second]}" 
foo with space, space bar 

Antwort

2

Hier ist eine traditionelle while-Schleife Ansatz ein assoziatives Array von einer Ausgabe des Befehls zu füllen:

while IFS= read -r; do 
    declare -A z+="($REPLY)" 
done < <(printf '[first]=foo [second]=bar\n[third]=baz\n') 

# check output 
$> echo "${z[first]}, ${z[second]}, ${z[third]}" 
foo, bar, baz 

# or declare -p 
$> declare -p z 
declare -A z='([third]="baz" [second]="bar" [first]="foo")' 

EDIT: Ihre ursprüngliche Versuch wird auch mit der richtigen Zitate arbeiten:

$> unset z 

$> declare -A z="($(echo '[first]=foo [second]=bar'))" 

$> declare -p z 
declare -A z='([second]="bar" [first]="foo")' 
+0

Das könnte funktionieren. Wir müßten ein 'IFS =' hinzufügen und wir können '$ '...' nicht um die ganze Sache herum verwenden oder es würde '\ t' in einen Tab usw. konvertieren, aber wir könnten es wahrscheinlich Erhalten Sie Literal-Zeilenumbrüche oder sogar NUL-Zeichen (und lesen Sie mit NUL-Flag) zwischen jedem Array-Element. Muss auch darüber nachdenken, danke! –

+1

Ich wurde einmal auf SO gesagt, dass 'IFS =' nicht benötigt wird, wenn wir interne '$ REPLY'-Variable verwenden, aber es schadet nicht, sie zu benutzen, denke ich. (bearbeitet) – anubhava

+0

Hmm, die Zeilenumbrüche machen eigentlich keinen Unterschied bei der Trennung der Werte. Das Skript funktioniert, wenn die Werte nur durch Leerzeichen getrennt sind. Der Printf benötigt nur einen Zeilenumbruch am Ende. –

1

Given, dass dies funktioniert:

declare -A z=([first]=$(echo 'foo') [second]=$(echo 'bar')) 

ich vermute, dass Bash das assoziative Array sehen muß initiali Liste, bevor Sie Auswechslungen vornehmen. Also ich sehe nicht ein Weg eval zu vermeiden:

eval "declare -A z=($(echo '[first]=foo [second]=bar'))" 

Was für einen „üblicher Grund“ ist eval zu vermeiden?

+4

Google [shell eval evil] (https://www.google.com/search?q=shell+eval+evil&ie=utf-8&oe=utf-8) für viele Diskussionen zu den Themen rund um 'eval'. Danke für die Antwort und hoffe immer noch, dass es eine Alternative gibt. –

+0

Sieht aus wie alles, was ich brauchte, war meine ursprüngliche Aufgabe zu zitieren, sehen Sie die Unterseite von http://stackoverflow.com/a/39418782/1745001. Ein bisschen peinlich ... Danke nochmal. –

2

Ich stelle mir vor, das ist etwas spröde, aber Sie können die gesamte z=(...) Zuweisung das Ergebnis einer Befehlsersetzung machen.

declare -A "$(echo z="($(echo '[first]=foo [second]=bar'))")" 
+0

Interessant. Daran hatte ich nicht gedacht. Wahrscheinlich möchte ich nicht 'echo z = ...' verwenden, aber eine Variation von 'printf 'z ="% s "....' könnte robust sein. Muss darüber nachdenken! Vielen Dank. –

+1

Die richtige Endung sollte ') sein.' '' '' '')) '', Aber das ist nicht genug für eine Bearbeitung :) –

+0

Ich denke, da gibt es keine unquoted '(' für die unquoted ')' zu paaren mit Es muss nicht zitiert werden. Wie auch immer, da ich mir sicher bin, dass eine andere Eingabe es wahrscheinlich von Arbeit zu Nicht-Arbeit bringen könnte. – chepner