Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: [PATCH (not final)] (take three?) unset "array[$anything]"



On Thu, Jun 3, 2021 at 6:14 AM Stephane Chazelas <stephane@xxxxxxxxxxxx> 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.

Attachment: test_unset.zsh
Description: Binary data



Messages sorted by: Reverse Date, Date, Thread, Author