On Sunday, December 14, 2014 02:39:29 PM Chet Ramey wrote: > And we get to the fundamental issue. Is it appropriate to require > arguments to declaration commands to be valid assignment statements when > the parser sees them, instead of when the builtin sees them, at least > when using the compound assignment syntax. > > I'm ok with tightening the rules and saying that it is, but it's not > backwards compatible and changes the behavior of things like > > declare -a foo='(1 2 3)' > > which I imagine plenty of people have used and has been a supported way > to do compound assignment for many years.
That would be one way but I think this can be solved without going quite so far. How do you feel about these rules? 1. If a word that is an argument to declare is parsed as a valid assignment, then perform the assignment immediately as it appears lexically. If such a word is parsed as a simple assignment (with or without an index) then bash treats it as a simple scalar assignment to the variable or array element as any ordinary assignment would. If word is parsed as an assignment with array initializer list then bash treats it as such. 2. Any words that do not parse as valid assignments lexically during step 1 undergo the usual set of expansions for simple commands and the resulting words are saved. 3. After evaluation of all words from steps 1-2, those that have undergone expansion per 2 are passed as arguments to declare. Declare then parses each of these arguments, testing for assignments that became valid as a result of expansion. During this step, for assignments to variables that have an array attribute set, or for all assignments if declare has been given the -a or -A option, declare will treat assignments that have initializer lists as array assignments accordingly. Otherwise, declare will treat all assignments as scalar assignments to a variable or array element. Words that still fail to parse as valid assignments are an error. I think this covers all the bases and is very close to the current behavior with one exception. All of the problems Stephane and I have brought up deal with the situation where a word that parses lexically as a scalar assignment isn't treated as such, so that is the only required change. I don't think that change will break many scripts. Some observations: * This solves the problem without breaking backwards compatibility and allows declare -p output to continue to function. * These rules will make the following become compatible with current ksh versions: $ ksh -c 'function f { typeset x[1]="(foo bar)"; typeset -p x; }; f' typeset -a x=([1]='(foo bar)') $ bash -c 'function f { typeset x[1]="(foo bar)"; typeset -p x; }; f' declare -a x='([0]="foo" [1]="bar")' * Treating words that parse as scalar assignments as scalar assignments is consistent with bash's usual treatment of "a[idx]=(foo)". If bash sees "declare foo[1]=(foo)", it should print: "bash: foo[1]: cannot assign list to array member". * Note the fine print in step 3. It deals with this case in bash's current behavior and doesn't need to change (-a vs no -a): $ bash -c 'x="[4]=foo [6]=bar"; declare -a "y=($x)"; declare -p y' declare -a y='([4]="foo" [6]="bar")' $ bash -c 'x="[4]=foo [6]=bar"; declare "y=($x)"; declare -p y' declare -- y="([4]=foo [6]=bar)" -- Dan Douglas