help-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Help-bash] Destroying arbitrary subset in an associative array?


From: Dan Douglas
Subject: Re: [Help-bash] Destroying arbitrary subset in an associative array?
Date: Sun, 18 Sep 2016 22:01:08 -0500

On Sun, Sep 18, 2016 at 2:10 PM, Mingye Wang (Arthur2e5)
<address@hidden> wrote:
> Hello,
>
> I have a set of functions in a script that wraps around operations in a
> certain associative array, $dict. When I try to unset a subset with quotes
> or backslashes, however, my "del" function always fail with "not a valid
> identifier". I am using bash 4.3.42.
>
> The problem boils down to this snippet:
>
>         declare -A dict
>         dict['"']=1
>         dict['`']=2
>         dict["'"]=3
>         dict['\']=4
>         declare -p dict
>
>         del(){ unset -v dict["$1"]; }
>         for k in "address@hidden"; do del "$k"; done
>
> I have also tried `unset dict["'"]` manually, which gives me "bad array
> subscript" instead.

Bash evaluates expansions in array indices dynamically as part of the
process of resolving its value. Often that means array indices must be
regarded as unexpanded strings that are dynamically evaluated later.

That solves this very problem (and many other less obvious ones) in
about the simplest possible way, at the cost of requiring everyone
know when to add extra quoting.

 ~ $ bash /dev/fd/9 9<<\EOF
typeset -A a=( [\\]= [\"]= [\)]= ) b
for x in "address@hidden"; do b[$x]=; done
b+=([\`]= [\]]=)
typeset -p b
for x in "address@hidden"; do
  unset -v 'b[$x]'
done
typeset -p b
EOF

declare -A b='(["\\"]="" ["]"]="" ["\`"]="" ["\""]="" [")"]="" )'
declare -A b='(["]"]="" ["\`"]="" )

Unfortunately, this isn't portable to ksh arrays because it wants to
know the type of the variable and its subscript and resolves it
immediately without evaluating expansions. On top of that, it's buggy
and can't parse assignment arguments and their expansions correctly.
One theoretically portable workaround is:

 ~ $ ksh /dev/fd/9 9<<\EOF
typeset -A a=( [\\]= [\"]= [\)]= ) b
for x in "address@hidden"; do b[$x]=; done
b+=([\`]= [\]]=)
typeset -p b
eval unset -v "$(printf -- 'b\[%q\] ' "address@hidden")"
typeset -p b
EOF

typeset -A b=(['"']='' [')']='' ['\']='' [']']='' ['`']='')
typeset -A b=(['\']='' ['`']='')

That doesn't work in bash. No idea why. I guess it's doing a
quote-removal step after the expansion even if there was nothing to
escape but a bare escape character.

 ~ $ bash -x /dev/fd/9 9<<\EOF
typeset -A a=( [\\]= [\"]= [\)]= ) b
for x in "address@hidden"; do b[$x]=; done
b+=([\`]= [\]]=)
typeset -p b
eval unset -v "$(printf -- 'b\[%q\] ' "address@hidden")"
typeset -p b
EOF

+ a=([\\]= [\"]= [\)]=)
+ typeset -A a b
+ for x in '"address@hidden"'
+ b[$x]=
+ for x in '"address@hidden"'
+ b[$x]=
+ for x in '"address@hidden"'
+ b[$x]=
+ b+=([\`]= [\]]=)
+ typeset -p b
declare -A b='(["\\"]="" ["]"]="" ["\`"]="" ["\""]="" [")"]="" )'
++ printf -- 'b\[%q\] ' '\' '"' ')'
+ eval unset -v 'b\[\\\] b\[\"\] b\[\)\] '
++ unset -v 'b[\]' 'b["]' 'b[)]'
/dev/fd/9: line 5: unset: `b[\]': not a valid identifier
/dev/fd/9: line 5: unset: `b["]': not a valid identifier
+ typeset -p b
declare -A b='(["\\"]="" ["]"]="" ["\`"]="" ["\""]="" )'



reply via email to

[Prev in Thread] Current Thread [Next in Thread]