On Thu, Jun 3, 2021 at 6:14 AM Stephane Chazelas wrote: > > If I understand correctly, the "stripquote" variant is the one > where the user can do: > > unset 'hash["foo"]' > > unset "hash['']" > > unset "hash[${(qq)key}]" > > That is where quotes are parsed and removed but otherwise > serve no purpose. I guess you can describe it that way, yes. > That hardly helps with backward compatibility as users who did > work around the previous behaviour will still have to adapt > their work around The point of my previous analysis is that they probably will not have to adapt. Your $MATCH workaround operates correctly with the stripquote version in nearly as many cases as it currently does (it is not foolproof for the current shell implementation). However, that doesn't mean I advocate for this over the "literal" variant. > and those who didn't (who did unset > "hash[$key]") will have their code choke on even more characters > (", $, ' in addition to the previous ones, and likely more > confusing behaviour when there are unmatched quotes or ()). I extended my test set to include a number of variations on those characters as well. I've attached the test script. Here are my test cases that fail if you just blindly do for k in ${(k)ax}; do unset "ax[$k]"; done typeset -p ax with appropriate trapping for the fatal errors. The literal variant gets all of these, leaving the test hash empty. Neither literal nor stripquote throws any errors, so the trap is only needed for the current implementation. Starting with that: typeset -A ax=( [$'\M-\C-@\\']=$'\M-\C-@\\' [$'\M-\C-@`']=$'\M-\C-@`' ['"${(@w)oops"']='"${(@w)oops"' ['(a']='(a' ['\$']='\$' ['\(']='\(' ['\)']='\)' ['\[']='\[' ['\\\']='\\\' ['\\\\']='\\\\' ['\]']='\]' ['\`']='\`' ) The cases that fail with the stripquote variation: typeset -A ax=( [$'\M-\C-@\\']=$'\M-\C-@\\' ['""']='""' ['"$oops"']='"$oops"' ['"safe"']='"safe"' ['"set"']='"set"' [\'\']=\'\' [\''safe'\']=\''safe'\' [\''set'\']=\''set'\' ['\!']='\!' ['\$']='\$' ['\(']='\(' ['\)']='\)' ['\*']='\*' ['\=']='\=' ['\@']='\@' ['\[']='\[' ['\\\']='\\\' ['\\\\']='\\\\' ['\]']='\]' ['\`']='\`' ['\s\a\f\e']='\s\a\f\e' ['\s\e\t']='\s\e\t' ) Current shell using $MATCH workaround: typeset -A ax=( [$'\M-\C-@`']=$'\M-\C-@`' ['"${(@w)oops"']='"${(@w)oops"' ['(']='(' ['(a']='(a' [')']=')' ['[']='[' ['\(']='\(' ['\)']='\)' ['\[']='\[' ['\`']='\`' ['`']='`' ) And stripquote with $MATCH workaround: typeset -A ax=( ['""']='""' ['"$oops"']='"$oops"' ['"safe"']='"safe"' ['"set"']='"set"' [\'\']=\'\' [\''safe'\']=\''safe'\' [\''set'\']=\''set'\' ['\`']='\`' ) Finally, literal with $MATCH workaround: typeset -A ax=( [$'\M-\C-@\\']=$'\M-\C-@\\' ['\']='\' ['\!']='\!' ['\$']='\$' ['\(']='\(' ['\)']='\)' ['\*']='\*' ['\=']='\=' ['\@']='\@' ['\[']='\[' ['\\\']='\\\' ['\`']='\`' ['\s\a\f\e']='\s\a\f\e' ['\s\e\t']='\s\e\t' [']']=']' ) I agree that the literal variation is probably the one most useful to re-apply in cases like read, print -v, etc.