Date: Tue, 27 Jun 2023 07:29:42 +0200 From: n952162 <n952...@web.de> Message-ID: <e3850500-84f6-c963-18ff-1a7a66063...@web.de>
I suspect this message really should have gone to the bash-help list. Never mind: | If so, why? I think this is related to the message I sent to the list early this morning (my time) -- bash is deciding what it has by looking at the characters in the line. In: l1=([a]=b [c]=d) it sees an assignment statement, with keys and values. In: l1=($(echo [a]=b [c]=d)) it doesn't, all that's there is an array assignment using the results of a command substitution for the values. At this point, there's no clue that what that list will contain will look like keys and values, so it is treated differently. | And how can I assign a list of members to an associative array? The first example above does that, but I am guessing you mean dynamically, rather than written into the script. eval "l1=($(echo [a]=b [c]=d))" will do that, as when the assignment is being parsed (by eval) the command substitution has already run (part of expanding the args passed to eval) and the actual assignment being run looks just like the first example - except it was dynamically generated by the command substitition. Or that is, it probably will - "echo" is not any kind of declaration utility, nor is it an assignment statement, so its args are parsed like args to any other command. That includes pathname expansion. If there happen to be files named a=b or c=d (or both) in the current directory, then those patterns (which is what they are when args to echo, or almost any other command) will be replaced by the expansions, and what will be executed by eval (if both those files exist) is eval "l1=(a=b c=d)" which is not what you intended. If those files (one or both) don't exist (and the relevant bash option to alter the default behaviour of a failure to match is not enabled) then the pattern that didn't match is left unchanged, so it seems to work. But only seems to, it is working by chance. You need to quote things that you don't want to be expanded if they appear in a context where they would be. So the command should really be eval "l1=($(echo '[a]=b' '[c]=d'))" Of course, this is a dummy test case, obviously, the real code which would be in that command substitution is, I assume, rather more complex. How to quote that, if quoting is needed at all, depends upon what is being executed. You are also relying upon field splitting happening, so the output from the command substitution isn't treated as a single string, but as two strings (I don't know bash array assignment syntax well enough to know if that matters, it might not). If a single string there is OK, and it seems to be, then eval "l1=("$(echo '[a]=b' '[c]=d')")" is even better, as that avoids issues if IFS doesn't contain what you expect it to contain at the time. kre ps: the single quotes only need to be around the '[' (and a \ before it could be used as well) but the form given above looks nicer, IMO. All that is really needed is to inhibit pathname expansion, by not having any unquoted glob chars there (* ? or [) where a '[' also needs a terminating unquoted ']', with something else between them, to count as a pattern char).