diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 571cc9f3..7916f4e9 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -10312,3 +10312,11 @@ subst.c resulting WORD_LIST * as if special == 0, because we don't want to quote the list for pattern matching. Report from Adjudicator Darren + + 5/14 + ---- +subst.c + - expand_array_subscript: add double quote (") to the list of characters + that are backslash-quoted in subscripts after word expansion. + skipsubscript treats them specially, so you have to quote them to + do things like `key='"' ; array[$key]=1 ; [[ -v array[$key] ]]' diff --git a/MANIFEST b/MANIFEST index f8b63bbe..9d9a1558 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1314,6 +1314,7 @@ tests/quotearray1.sub f tests/quotearray2.sub f tests/quotearray3.sub f tests/quotearray4.sub f +tests/quotearray5.sub f tests/read.tests f tests/read.right f tests/read1.sub f diff --git a/subst.c b/subst.c index 579de3f6..15979bd9 100644 --- a/subst.c +++ b/subst.c @@ -10199,6 +10199,7 @@ expand_array_subscript (string, sindex, quoted, flags) abstab[LBRACK] = abstab[RBRACK] = 1; abstab['$'] = abstab['`'] = abstab['~'] = 1; abstab['\\'] = abstab['\''] = 1; + abstab['"'] = 1; /* XXX */ /* We don't quote `@' or `*' in the subscript at all. */ } diff --git a/tests/quotearray.right b/tests/quotearray.right index c106f7a7..1a907411 100644 --- a/tests/quotearray.right +++ b/tests/quotearray.right @@ -21,17 +21,17 @@ declare -A A=(["~"]="43" ["~0"]="43" ) declare -a a=([0]="12" [1]="42") 2 2 -declare -Ai assoc=(["']"]="2" ["\$var"]="1" ) +declare -Ai assoc=(["']"]="3" ["\$var"]="1" ) 105 declare -A assoc=(["\` echo >&2 foo\`"]="42" ["\$( echo >&2 bar)"]="63" ) -./quotearray.tests: line 139: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)") -./quotearray.tests: line 143: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)") +./quotearray.tests: line 140: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)") +./quotearray.tests: line 144: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)") 1 -./quotearray.tests: line 146: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)") +./quotearray.tests: line 147: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)") 1 -./quotearray.tests: line 149: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)") +./quotearray.tests: line 150: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)") 1 -./quotearray.tests: line 152: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)") +./quotearray.tests: line 153: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)") 1 declare -A assoc 0 @@ -57,8 +57,11 @@ foo 0 1 1 -./quotearray1.sub: line 111: test: aa[$(echo: binary operator expected +./quotearray1.sub: line 113: test: aa[$(echo: binary operator expected 2 +[[ -v assoc[a] ]]; $?=0 +[[ -v assoc["] ]]; $?=0 +declare -A assoc=(["\""]="123" [a]="123" ) declare -A a=([1]="1" [0]="0" [" "]="11" ) 7 7 @@ -80,18 +83,23 @@ declare -A assoc=(["\$var"]="value" ) declare -A assoc=(["\$var"]="value" ) declare -A assoc=(["\$var"]="value" ) declare -A assoc=() -declare -A a=() declare -A a=(["\$(echo foo)"]="1" ) declare -A a=() declare -A a=(["\$(echo foo)"]="1" ) +declare -A a=(["\$(echo foo)"]="1" ) declare -A assoc=(["!"]="bang" ) 1 1 declare -A assoc=(["!"]="bang" ["@"]="at" ) declare -A assoc=(["!"]="bang" ) declare -a array=([0]="1" [1]="2" [2]="3") -./quotearray3.sub: line 93: declare: array: not found -./quotearray3.sub: line 97: declare: array: not found +./quotearray3.sub: line 94: declare: array: not found +./quotearray3.sub: line 98: declare: array: not found +declare -A map=(["foo\$(uname >/dev/tty)bar"]="1" ) +1 +declare -A map=() +$(DOESNOTEXIST) +declare -A blah=() declare -A assoc=(["*"]="star" ["!"]="bang" ["@"]="at" ) declare -A assoc=(["*"]="star" ["!"]="bang" ) declare -A assoc=(["!"]="bang" ) @@ -119,3 +127,26 @@ declare -a array=([0]="1" [1]="2" [2]="3") 0 ./quotearray4.sub: line 115: array[@]: bad array subscript declare -a array=([0]="1" [1]="2" [2]="3") +./quotearray5.sub: line 27: unset: `a[$(echo': not a valid identifier +./quotearray5.sub: line 27: unset: `foo)]': not a valid identifier +declare -A a=() +declare -A a=() +declare -A a=() +----- +declare -A a=(["\$(echo foo)"]="1" ) +declare -A a=() +declare -A a=() +declare -A a=() +----- +declare -A a=() +declare -A a=() +declare -A a=() +---------- +declare -A a=([.]="v1" ) +declare -A a=([.]="v1" ) +----- +declare -A a=([.]="v1" ) +declare -A a=([.]="v1" ) +----- +declare -A a=([.]="v1" ) +declare -A a=([.]="v1" ) diff --git a/tests/quotearray.tests b/tests/quotearray.tests index 83e50ad8..e1ed83b0 100644 --- a/tests/quotearray.tests +++ b/tests/quotearray.tests @@ -119,6 +119,7 @@ declare -Ai assoc assoc[$var]=1 assoc[$var]+=1 ((assoc['$var']++)) +((assoc[$var]++)) typeset -p assoc unset assoc @@ -158,3 +159,6 @@ ${THIS_SH} ./quotearray3.sub # behavior of builtins with array subscripts @ and * ${THIS_SH} ./quotearray4.sub + +# behavior of unset with quoted and unquoted array arguments +${THIS_SH} ./quotearray5.sub diff --git a/tests/quotearray1.sub b/tests/quotearray1.sub index cda30770..19741b1f 100644 --- a/tests/quotearray1.sub +++ b/tests/quotearray1.sub @@ -91,6 +91,8 @@ echo $? [[ -v assoc['$key4'] ]] echo $? +unset -v assoc + declare -A aa aa[$key5]=foo @@ -112,3 +114,18 @@ test -v aa[$key6] echo $? unset aa key + +declare -A assoc + +mytest () +{ + assoc["$1"]=123 + [[ -v assoc["$1"] ]] + printf '[[ -v assoc[%s] ]]; $?=%s\n' "$1" "$?" +} + +mytest 'a' +mytest '"' +declare -p assoc +unset -v assoc +unset -f mytest diff --git a/tests/quotearray2.sub b/tests/quotearray2.sub index d7ae8176..056f8ca2 100644 --- a/tests/quotearray2.sub +++ b/tests/quotearray2.sub @@ -101,3 +101,7 @@ declare -p assoc shopt -s assoc_expand_once test -v assoc["$key"] ; echo $? + +unset assoc +shopt -u assoc_expand_once + diff --git a/tests/quotearray3.sub b/tests/quotearray3.sub index 43487630..65f950d5 100644 --- a/tests/quotearray3.sub +++ b/tests/quotearray3.sub @@ -33,6 +33,7 @@ unset 'assoc[$var]' declare -p assoc unset assoc +shopt -u assoc_expand_once declare -A a a['$(echo foo)']=1 @@ -95,3 +96,22 @@ declare -p array BASH_COMPAT=51 unset array[@] declare -p array + +declare -A map; key='foo$(uname >/dev/tty)bar'; map[$key]=1 +declare -p map +echo ${map["$key"]} + +unset map["$key"] +declare -p map +unset map + +declare -A blah +blah['$(DOESNOTEXIST)']=broken +for i in "${!blah[@]}"; do echo "$i"; done + +for i in "${!blah[@]}"; do unset blah["$i"]; done +declare -p blah +unset blah + + + diff --git a/tests/quotearray5.sub b/tests/quotearray5.sub new file mode 100644 index 00000000..5366a999 --- /dev/null +++ b/tests/quotearray5.sub @@ -0,0 +1,124 @@ +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# a set of tests for unset to try to ensure that subscripts are only expanded +# once. Derived from tests submitted by konsolebox@gmail.com + +declare -A a +key='$(echo foo)' + +# Here the tokens are valid array references and pass that fact to unset +# post-expansion + +# This solves the surprise expansion issues. + +a[$key]=1 +unset -v a[$key] # this performs normal word splitting +unset -v a["$key"] # prevent word splitting +declare -p a # Displays no element + +a['$key']=2 +unset -v a['$key'] +declare -p a # Displays no element + +a["foo"]=3 +unset -v a["foo"] +declare -p a # Displays no element + +echo ----- + +# Here the tokens are "strings". They expand and keep the +# original behavior and allows existing scripts to not break. +# It also allows nref or iref references to be transparently +# referenced in it. + +# the quotes prevent the arguments from being recognized as valid array +# references before word expansion. since unset doesn't know to treat +# them specially, they're treated as in previous versions and expansion +# is performed as part of evaluating the subscript + +a[$key]=1 +declare -p a +unset 'a[$key]' # Transforms to a[$key] after expansion +declare -p a # Displays no element + +a['$key']=2 +unset "a['\$key']" # Transforms to a['$key'] after expansion +declare -p a # Displays no element + +a["foo"]=3 +unset 'a["foo"]' # Transforms to a["foo"] after expansion +declare -p a # Displays no element + +echo ----- + +# The update also keeps compatibility with already existing behavior of +# unset when assoc_expand_once is enabled, but only for quoted tokens. + +a=() +shopt -s assoc_expand_once + +a[$key]=1 +unset "a[$key]" +declare -p a # Displays no element + +a['$key']=2 +unset "a[\$key]" +declare -p a # Displays no element + +a["foo"]=3 +unset "a[foo]" +declare -p a # Displays no element + +echo ---------- + +# For unsetting '@' and all elements: + +key=@ + +declare -A a=(@ v0 . v1) +unset a[$key] +declare -p a # Displays 'declare -A a=([.]="v1" )' + +declare -A a=(@ v0 . v1) +unset a[@] +declare -p a # same behavior + +echo ----- + +# these are quoted strings and unset doesn't treat them specially + +unset a +shopt -u assoc_expand_once + +declare -A a=(@ v0 . v1) +unset 'a[$key]' +declare -p a # Displays 'declare -A a=([.]="v1" )' + +declare -A a=(@ v0 . v1) +unset 'a[@]' +declare -p a # same behavior + +echo ----- + +unset a +shopt -s assoc_expand_once + +declare -A a=(@ v0 . v1) +unset "a[$key]" # $key is expanded +declare -p a # Displays 'declare -A a=([.]="v1" )' + +declare -A a=(@ v0 . v1) +unset 'a[@]' +declare -p a # same behavior