diff options
Diffstat (limited to 'tests')
157 files changed, 4198 insertions, 257 deletions
diff --git a/tests/alias.right b/tests/alias.right index 9e33036b..76f32076 100644 --- a/tests/alias.right +++ b/tests/alias.right @@ -2,6 +2,7 @@ alias: 0 alias: 0 ./alias.tests: line 38: qfoo: command not found quux +hi bar value bar @@ -40,3 +41,5 @@ baz foo bar baz +<áa> +<aá> diff --git a/tests/alias.tests b/tests/alias.tests index 0280c16d..15eac5b1 100644 --- a/tests/alias.tests +++ b/tests/alias.tests @@ -49,8 +49,17 @@ foo bar unalias foo bar baz +# post bash-5.1 problems with compound array assignment during multiline +# alias expansion +alias foo='a=() b="" +for i in 1; do echo hi; done' +foo + +unalias foo + ${THIS_SH} ./alias1.sub ${THIS_SH} ./alias2.sub ${THIS_SH} ./alias3.sub ${THIS_SH} ./alias4.sub ${THIS_SH} ./alias5.sub +${THIS_SH} ./alias6.sub diff --git a/tests/alias6.sub b/tests/alias6.sub new file mode 100644 index 00000000..d2d7daf5 --- /dev/null +++ b/tests/alias6.sub @@ -0,0 +1,13 @@ +# make sure aliases that end in multibyte characters don't interfere with the +# space sentinel alias expansion adds; problem through bash-5.1 +shopt -s expand_aliases + +LC_ALL=en_US.UTF-8 + +alias a1='printf "<%s>\\n" áa' +a1 + +alias a2='printf "<%s>\\n" aá' +a2 + +unalias a1 a2 diff --git a/tests/arith.right b/tests/arith.right index c74602e3..02687815 100644 --- a/tests/arith.right +++ b/tests/arith.right @@ -259,5 +259,5 @@ efg 42 42 42 -./arith.tests: line 327: 'foo' : syntax error: operand expected (error token is "'foo' ") -./arith.tests: line 331: b[c]d: syntax error in expression (error token is "d") +./arith.tests: line 330: 'foo' : syntax error: operand expected (error token is "'foo' ") +./arith.tests: line 333: b[c]d: syntax error in expression (error token is "d") diff --git a/tests/arith.tests b/tests/arith.tests index 1a3501aa..e9ab5765 100644 --- a/tests/arith.tests +++ b/tests/arith.tests @@ -322,10 +322,12 @@ printf "%u\n" $n echo $(( 16#$(printf "%x\n" $n) )) echo $(( 16#$(printf "%X\n" $n) )) +# allow reserved words after an arithmetic command just because +if ((expr)) then ((expr)) fi + # these are errors foo=1 echo $(( 'foo' )) - # causes longjmp botches through bash-2.05b a[b[c]d]=e diff --git a/tests/array-at-star b/tests/array-at-star index 80f039d2..80f039d2 100755..100644 --- a/tests/array-at-star +++ b/tests/array-at-star diff --git a/tests/array.right b/tests/array.right index 2d1c51db..62278852 100644 --- a/tests/array.right +++ b/tests/array.right @@ -67,6 +67,7 @@ declare -ar a=([1]="" [2]="bdef" [5]="hello world" [6]="test expression" [15]="t declare -a b=([0]="this" [1]="is" [2]="a" [3]="test" [4]="" [5]="/etc/passwd") declare -ar c declare -a d=([1]="test test") +declare -a e=() declare -a f=([0]="" [1]="bdef" [2]="hello world" [3]="test" [4]="ninth element") ./array.tests: line 135: unset: ps1: not an array variable ./array.tests: line 139: declare: c: cannot destroy array variables in this way @@ -84,6 +85,7 @@ declare -ar a=([1]="" [2]="bdef" [5]="hello world" [6]="test expression" [15]="t declare -a b=([0]="this" [1]="is" [2]="a" [3]="test" [4]="" [5]="/etc/passwd") declare -ar c declare -a d=([1]="test test") +declare -a e=() declare -a f=([0]="" [1]="bdef" [2]="hello world" [3]="test" [4]="ninth element") declare -a rv=([0]="this" [1]="is" [2]="a" [3]="test" [4]="of" [5]="read" [6]="using" [7]="arrays") abde @@ -381,6 +383,8 @@ strlen(4four) = 5 1 2 0 3 1 2 0 3 1 2 0 3 +declare -ai arr=([0]="2" [1]="4" [2]="6") +declare -a arr=([0]="hello" [1]="world") foo index 1: ok foo index 2: ok foo: implicit reference to element 0: ok @@ -492,8 +496,8 @@ x b c declare -a a=([1]="2" [2]="3" [3]="4") abcd unset -./array21.sub: line 30: typeset: a: not found -./array21.sub: line 33: typeset: A: not found +declare -a a=() +declare -A A=([four]="4" [two]="2" [three]="3" [one]="1" ) declare -a a=() declare -A A=() declare -a foo=([0]="1" [1]="(4 5 6)" [2]="3") @@ -520,13 +524,11 @@ argv[1] = <y> <X> <X> <X> <X> ./array23.sub: line 22: $( echo >&2 foo ) : syntax error: operand expected (error token is "$( echo >&2 foo ) ") ./array23.sub: line 23: $( echo >&2 foo ) : syntax error: operand expected (error token is "$( echo >&2 foo ) ") -foo -0 -foo -foo -foo -6 -./array23.sub: line 34: $( echo >&2 foo ): syntax error: operand expected (error token is "$( echo >&2 foo )") +./array23.sub: line 24: $( echo >&2 foo ) : syntax error: operand expected (error token is "$( echo >&2 foo ) ") +./array23.sub: line 26: $( echo >&2 foo ) : syntax error: operand expected (error token is "$( echo >&2 foo ) ") +./array23.sub: line 30: $( echo >&2 foo ): syntax error: operand expected (error token is "$( echo >&2 foo )") +./array23.sub: line 33: $( echo >&2 foo ): syntax error: operand expected (error token is "$( echo >&2 foo )") +./array23.sub: line 34: $index: syntax error: operand expected (error token is "$index") ./array23.sub: line 35: $( echo >&2 foo ): syntax error: operand expected (error token is "$( echo >&2 foo )") 0 0 @@ -743,23 +745,43 @@ argv[1] = <b> argv[2] = <a> argv[1] = <b+a> 7 -./array27.sub: line 24: a[]]=7 : syntax error: invalid arithmetic operator (error token is "]=7 ") +7 declare -A A=([$'\t']="2" [" "]="2" ) -./array27.sub: line 36: ((: A[]]=2 : syntax error: invalid arithmetic operator (error token is "]=2 ") -declare -A A=([$'\t']="2" ["*"]="2" [" "]="2" ["@"]="2" ) -./array27.sub: line 45: A[]]: bad array subscript +declare -A A=([$'\t']="2" ["*"]="2" [" "]="2" ["]"]="2" ["@"]="2" ) +declare -A A=([$'\t']="2" ["*"]="2" [" "]="2" ["]"]="2" ["@"]="2" ) +./array27.sub: line 52: read: `A[]]': not a valid identifier declare -A A=([$'\t']="X" ["*"]="X" [" "]="X" ["@"]="X" ) -./array27.sub: line 53: A[]]: bad array subscript +./array27.sub: line 60: printf: `A[]]': not a valid identifier declare -A A=([$'\t']="X" ["*"]="X" [" "]="X" ["@"]="X" ) -./array27.sub: line 61: declare: `A[]]=X': not a valid identifier +./array27.sub: line 68: declare: `A[]]=X': not a valid identifier +declare -A A=(["*"]="X" ["@"]="X" ) +./array27.sub: line 76: declare: `A[]]=X': not a valid identifier declare -A A=(["*"]="X" ["@"]="X" ) -./array27.sub: line 69: declare: `A[]]=X': not a valid identifier -./array27.sub: line 69: A[*]: bad array subscript -./array27.sub: line 69: A[@]: bad array subscript -declare -A A declare -a bug4=([0]="" [1]="5" [2]="" [3]="1" [4]="") declare -a bug=([0]="" [1]="5" [2]="" [3]="1" [4]="") declare -a bug2=([0]="") declare -a bug3=([0]="" [1]="5" [2]="" [3]="1" [4]="") declare -a not_bug=([0]="no" [1]="nulls") declare -a workaround=([0]="") +declare -a var=([0]=$'\001\001\001\001') +declare -A v2=([$'\001']=$'ab\001c' ) +declare -a foo=([0]=$'\001\001\001\001') +declare -A foo=([$'\001']=$'ab\001c' ) +declare -a foo=([0]=$'\001\001\001\001') +declare -a foo=([0]=$'\001\001\001\001') +declare -A foo=([v]=$'\001\001\001\001' ) +declare -A foo=([v]=$'\001\001\001\001' ) +declare -A foo=([$'\001']=$'ab\001c' ) +declare -A foo=([$'\001']=$'ab\001c' ) +foo +declare -a a=([42]="foo") +foo +declare -a a=([42]="foo") +7 +declare -ai a=([42]="7") +42 +declare -ai a=([42]="42") +FOO +declare -Au A=([Darwin]="FOO" ) +FOO +declare -Au A=(["@"]="FOO" ) diff --git a/tests/array.tests b/tests/array.tests index ba8e2254..d0bb08b7 100644 --- a/tests/array.tests +++ b/tests/array.tests @@ -425,3 +425,5 @@ ${THIS_SH} ./array25.sub ${THIS_SH} ./array26.sub ${THIS_SH} ./array27.sub ${THIS_SH} ./array28.sub +${THIS_SH} ./array29.sub +${THIS_SH} ./array30.sub diff --git a/tests/array15.sub b/tests/array15.sub index 47796b95..12f5391e 100644 --- a/tests/array15.sub +++ b/tests/array15.sub @@ -35,3 +35,18 @@ func() func echo "${foo[@]}" + +unset foo + +# test options to declare that disable attributes that affect how values +# are expanded +# +# we already handle options that set attributes specially, so we should +# handle attributes that unset those attributes specially as well + +unset arr +declare -i -a arr=(1+1 2+2 3+3) +declare -p arr + +declare +i arr=(hello world) +declare -p arr diff --git a/tests/array27.sub b/tests/array27.sub index 44ed444d..e2a1e708 100644 --- a/tests/array27.sub +++ b/tests/array27.sub @@ -40,6 +40,13 @@ declare -p A unset A declare -A A +for k in ']' '*' '@' $'\t' ' '; do + A[$k]=2 +done +declare -p A + +unset A +declare -A A for k in $'\t' ' ' ']' '*' '@'; do read "A[$k]" <<< X @@ -69,4 +76,3 @@ for k in ']' '*' '@'; do declare "A[$k]=X" done declare -p A - diff --git a/tests/array29.sub b/tests/array29.sub new file mode 100644 index 00000000..f73c2d1c --- /dev/null +++ b/tests/array29.sub @@ -0,0 +1,86 @@ +# 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 <http://www.gnu.org/licenses/>. +# +# Issues with CTLESC characters in array subscripts and values. Bash-5.1 and +# earlier didn't quote them correctly and therefore halved the number of +# CTLESCs. + +declare -a var +var=( $'\x01\x01\x01\x01' ) +declare -p var +declare -A v2 +v2=( $'\x01' ab$'\x01'c ) +declare -p v2 + +pv() +{ + local -a foo + foo=( "${var[@]}" ) + declare -p foo +} +pv + +unset -f pv +pv() +{ + local -A foo + eval foo=\( "${v2[@]@k}" \) + declare -p foo +} +pv + +# these are wrong through bash-5.1; there is a fix tagged for bash-5.2 +# when I uncomment that fix, these results will reflect it + +pv1() +{ + local -a foo=( "${var[@]}" ) + declare -p foo +} +pv1 + +pv2() +{ + local -a foo=( [0]="${var[@]}" ) + declare -p foo +} +pv2 + +pv3() +{ + local -A foo=( v "${var[@]}" ) + declare -p foo +} +pv3 + +pv4() +{ + local -A foo=( [v]="${var[@]}" ) + declare -p foo +} +pv4 + +unset -f pv3 pv4 +pv3() +{ + local -A foo=( $'\x01' "${v2[@]}" ) + declare -p foo +} +pv3 + +pv4() +{ + local -A foo=( [$'\x01']="${v2[@]}" ) + declare -p foo +} +pv4 diff --git a/tests/array30.sub b/tests/array30.sub new file mode 100644 index 00000000..14f97980 --- /dev/null +++ b/tests/array30.sub @@ -0,0 +1,46 @@ +# 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 <http://www.gnu.org/licenses/>. +# +declare -a a +a=() + +echo ${a[42]=foo} +declare -p a + +a=() +echo ${a[$(echo 42)]=foo} +declare -p a + +unset a + +declare -ai a +a=() +echo ${a[42]=4+3} +declare -p a + +a=() +echo ${a[$(echo 42)]=42} +declare -p a + +unset a + +declare -A A +declare -u A +A=() +echo ${A[$(echo Darwin)]=foo} + +declare -p A +A=() + +echo ${A[@]:=foo} +declare -p A diff --git a/tests/assoc.right b/tests/assoc.right index e9aa9172..9a1662c4 100644 --- a/tests/assoc.right +++ b/tests/assoc.right @@ -16,25 +16,24 @@ declare -A wheat=([two]="b" [three]="c" [one]="a" [zero]="0" ) declare -A chaff=(["hello world"]="flip" [one]="10" [zero]="5" ) ./assoc.tests: line 51: waste: readonly variable ./assoc.tests: line 52: unset: waste: cannot unset: readonly variable -./assoc.tests: line 53: chaff[*]: bad array subscript -./assoc.tests: line 54: [*]=12: invalid associative array key -declare -A chaff=(["hello world"]="flip" [one]="a" ) +declare -A chaff=(["*"]="12" ["hello world"]="flip" [one]="a" ) flip argv[1] = <multiple> argv[2] = <words> +argv[3] = <12> +argv[4] = <flip> +argv[5] = <a> +argv[1] = <multiple words> +argv[2] = <12> argv[3] = <flip> argv[4] = <a> -argv[1] = <multiple words> -argv[2] = <flip> -argv[3] = <a> argv[1] = <multiple> argv[2] = <words> -argv[3] = <flip> -argv[4] = <a> -argv[1] = <multiple words flip a> +argv[3] = <12> +argv[4] = <flip> +argv[5] = <a> +argv[1] = <multiple words 12 flip a> ./assoc.tests: line 71: declare: chaff: cannot destroy array variables in this way -./assoc.tests: line 73: chaff[*]: bad array subscript -./assoc.tests: line 74: [*]=12: invalid associative array key declare -A wheat=([six]="6" ["foo bar"]="qux qix" ) argv[1] = <qux> argv[2] = <qix> @@ -200,11 +199,7 @@ declare -A hash=([key]="value1 value2" ) declare -A b=([")"]="" ["\""]="" ["]"]="" ["\\"]="" ["\`"]="" ) declare -A b=(["]"]="" ["\`"]="" ) declare -A dict=(["'"]="3" ["\""]="1" ["\\"]="4" ["\`"]="2" ) -./assoc9.sub: line 36: unset: `dict[']': not a valid identifier -./assoc9.sub: line 36: unset: `dict["]': not a valid identifier -./assoc9.sub: line 36: unset: `dict[\]': not a valid identifier -./assoc9.sub: line 36: unset: `dict[`]': not a valid identifier -declare -A dict=(["'"]="3" ["\""]="1" ["\\"]="4" ["\`"]="2" ) +declare -A dict=() declare -A dict=(["'"]="3" ["\""]="1" ["\\"]="4" ["\`"]="2" ) declare -A dict=() 4 @@ -223,6 +218,14 @@ declare -A a=(["80's"]="Depeche Mode" ) declare -A a=(["\$(date >&2)"]="5" ) declare -A myarray=([foo]="bleh" ["foo[bar"]="bleh" ) foo +declare -A assoc=(["\$var"]="value" ) +declare -A assoc=(["\$var"]="value" ) +declare -A assoc=(["\$var"]="value" ) +declare -A assoc=() +./assoc9.sub: line 154: typeset: `foo[foo]bar]=bax': not a valid identifier +foo]bar +bip +declare -A foo=(["foo]bar"]="bip" ) ./assoc10.sub: line 14: declare: a: cannot convert indexed to associative array f: declare -a a ./assoc10.sub: line 17: declare: a: cannot convert associative to indexed array @@ -250,11 +253,148 @@ declare -A dict=(["?"]="quest" ["*"]="star" ["'"]="squote" ["\$"]="dol" ["\""]=" dict=( "?" "quest" "*" "star" "'" "squote" "\$" "dol" "\"" "dquote" "\\" "bslash" "@" "at" "}" "rbrace" "{" "lbrace" "\`" "bquote" ) declare -A foo=([two]="" [one]="1" ) foo=( two "" one "1" ) -rparen dquote rbrace bs -declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbrace" ["\\"]="bs" ) -")" "rparen" "\"" "dquote" "]" "rbrace" "\\" "bs" -declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbrace" ["\\"]="bs" ) -declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbrace" ["\\"]="bs" ) -declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbrace" ["\\"]="bs" ) +rparen dquote rbracket bs +declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbracket" ["\\"]="bs" ) +")" "rparen" "\"" "dquote" "]" "rbracket" "\\" "bs" +declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbracket" ["\\"]="bs" ) +declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbracket" ["\\"]="bs" ) +declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbracket" ["\\"]="bs" ) declare -Arx foo=([two]="2" [three]="3" [one]="1" ) ./assoc11.sub: line 90: foo: readonly variable +declare -A v1=(["1 2"]="3" ) +declare -A v2=(["1 2"]="3" ) +declare -A v3=(["1 2"]="3" ) +declare -A v1=(["1 2"]="3 4 5" ) +declare -A v2=(["1 2"]="3 4 5" ) +declare -A v3=(["1 2"]="3 4 5" ) +declare -A v1=(["1 2"]="3 4 5" ) +declare -A v2=(["1 2"]="3 4 5" ) +declare -A v3=(["1 2"]="3 4 5" ) +declare -A v1=(["1 2"]="3 4 5" ) +declare -A v2=(["1 2"]="3 4 5" ) +declare -A v3=(["1 2"]="3 4 5" ) +declare -A v1=(["20 40 80"]="xtra" ["1 2"]="3 4 5" ) +declare -A v2=(["20 40 80"]="xtra" ["1 2"]="3 4 5" ) +declare -A v3=(["1 2"]="3 4 5" ["\$xtra"]="xtra" ) +declare -A v1=(["20 40 80"]="new xtra" ["1 2"]="3 4 5" ) +declare -A v2=(["20 40 80"]="new xtra" ["1 2"]="3 4 5" ) +declare -A v3=(["1 2"]="3 4 5" ["\$xtra"]="new xtra" ) +declare -A assoc=(["*"]="star" ["!"]="bang" ["@"]="at" ) +at +star +declare -A a=(["@"]="at" ) +./assoc13.sub: line 22: ia[@]: bad array subscript +declare -a ia +declare -A a=(["@"]="at2" ) +declare -A a=(["@"]=" string" ) +declare -A a=(["*"]="star2" ["@"]="at" ) +declare -A assoc=([hello]="world" ["key with spaces"]="value with spaces" [foo]="bar" [one]="1" ) +argv[1] = <world> +argv[2] = <value with spaces> +argv[3] = <bar> +argv[4] = <1> +argv[1] = <hello> +argv[2] = <world> +argv[3] = <key with spaces> +argv[4] = <value with spaces> +argv[5] = <foo> +argv[6] = <bar> +argv[7] = <one> +argv[8] = <1> +argv[1] = <world value with spaces bar 1> +argv[1] = <hello world key with spaces value with spaces foo bar one 1> +argv[1] = <hello> +argv[2] = <world> +argv[3] = <key with spaces> +argv[4] = <value with spaces> +argv[5] = <one> +argv[6] = <1> +argv[7] = <foo> +argv[8] = <bar> +argv[1] = <'hello'> +argv[2] = <'world'> +argv[3] = <'key with spaces'> +argv[4] = <'value with spaces'> +argv[5] = <'one'> +argv[6] = <'1'> +argv[7] = <'foo'> +argv[8] = <'bar'> +argv[1] = <'hello'> +argv[2] = <'world'> +argv[3] = <'key with spaces'> +argv[4] = <'value with spaces'> +argv[5] = <'one'> +argv[6] = <'1'> +argv[7] = <'foo'> +argv[8] = <'bar'> +declare -A clone=([hello]="world" ["key with spaces"]="value with spaces" [foo]="bar" [one]="1" ) +declare -A posparams=([hello]="world" ["key with spaces"]="value with spaces" [foo]="bar" [one]="1" ) +declare -A var=([$'\001']=$'\001\001\001\001' ) +declare -A v2=([$'\001']=$'\001\001\001\001' ) +argv[1] = <^A> +argv[2] = <^A^A^A^A> +declare -A foo=([$'\001']=$'\001\001\001\001' ) +declare -A var=([$'\001']=$'\001\001\001\001' ) +argv[1] = <^A> +argv[2] = <^A^A^A^A> +declare -A foo=([$'\001']=$'\001\001\001\001' ) +declare -A var=([$'\001']=$'\001\001\001\001' ) +argv[1] = <^A> +argv[2] = <^A^A^A^A> +declare -A foo=([$'\001']=$'\001\001\001\001' ) +declare -a var=([0]=$'\001\001\001\001') +argv[1] = <$'\001\001\001\001'> +declare -a foo=([0]=$'\001\001\001\001') +declare -a var=([0]=$'\001\001\001\001') +argv[1] = <$'\001\001\001\001'> +declare -a foo=([0]=$'\001\001\001\001') +declare -A var=([two]=$'ab\001cd' [one]=$'\001\001\001\001' ) +declare -A foo=([two]=$'ab\001cd' [one]=$'\001\001\001\001' ) +declare -A foo=([$'\001']=$'ab\001cd' ) +declare -A foo=([$'\001']=$'\001\001\001\001' ) +declare -A A=(["\$(echo Darwin ; echo stderr>&2)"]="darjeeling" [Darwin]="darjeeling" ) +stderr +darjsharking +darjsharking +stderr +darj +darj +stderr +DARJEELING +DARJEELING +stderr +'darjeeling' +'darjeeling' +stderr +darjeel +darjeel +stderr +10 +10 +stderr +darjeeling +darjeeling +stderr +set +set +stderr +set +set +stderr +42 +42 +declare -A A=(["]"]="rbracket" ["["]="lbracket" ) +declare -A A=() +declare -A A=(["]"]="rbracket" ["["]="lbracket" ) +declare -A A=() +declare -A A=(["]"]="rbracket" ["["]="lbracket" ) +declare -A A=() +declare -A A=(["]"]="rbracket" ["["]="lbracket" ) +declare -A A=() +declare -A A=(["]"]="rbracket" ["["]="lbracket" ) +declare -A A=() +declare -A A=(["]"]="rbracket" ["["]="lbracket" ) +declare -A A=() +declare -A A=(["]"]="rbracket" ["["]="lbracket" ) +declare -A A=() +5: ok 1 diff --git a/tests/assoc.tests b/tests/assoc.tests index 8d5c8927..c656536b 100644 --- a/tests/assoc.tests +++ b/tests/assoc.tests @@ -47,7 +47,7 @@ declare +i chaff chaff[hello world]=flip declare -p chaff -# TEST - errors +# TEST - no longer errors waste[stuff]=other unset waste chaff[*]=12 @@ -244,3 +244,25 @@ ${THIS_SH} ./assoc10.sub # test assigning associative arrays using compound key/value pair assignments ${THIS_SH} ./assoc11.sub + +# more kvpair associative array assignment tests +${THIS_SH} ./assoc12.sub + +# assignment to @ and * +${THIS_SH} ./assoc13.sub + +# tests of the @k transformation on associative arrays +${THIS_SH} ./assoc14.sub + +# tests with subscripts and values containing 0x01 (some indexed array tests too) +${THIS_SH} ./assoc15.sub + +# tests with subscripts being expanded more than one in ${xxx} word expansions +${THIS_SH} ./assoc16.sub + +# tests with `[' and `]' subscripts and `unset' +${THIS_SH} ./assoc17.sub + +# tests with `[' and `]' subscripts and printf/read/wait builtins +${THIS_SH} ./assoc18.sub + diff --git a/tests/assoc11.sub b/tests/assoc11.sub index 13111a52..9d9afae9 100644 --- a/tests/assoc11.sub +++ b/tests/assoc11.sub @@ -69,7 +69,7 @@ foo=(one 1 two) declare -p foo echo foo=\( ${foo[@]@K} \) -typeset -A a=( [\\]=bs [\"]=dquote [\)]=rparen [\]]=rbrace ) +typeset -A a=( [\\]=bs [\"]=dquote [\)]=rparen [\]]=rbracket ) echo ${a[@]} declare -p a diff --git a/tests/assoc12.sub b/tests/assoc12.sub new file mode 100644 index 00000000..359dc0b3 --- /dev/null +++ b/tests/assoc12.sub @@ -0,0 +1,74 @@ +# 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 <http://www.gnu.org/licenses/>. +# +foo='1 2' +bar='3 4 5' +xtra='20 40 80' + +declare -A v1=( $foo 3 ) +declare -p v1 + +declare -A v2=( [$foo]=3 ) +declare -p v2 + +declare -A v3 +v3=( $foo 3 ) +declare -p v3 + +unset v1 v2 v3 + +declare -A v1=( $foo $bar ) +declare -p v1 + +declare -A v2=( [$foo]=$bar ) +declare -p v2 + +declare -A v3 +v3=( $foo $bar ) +declare -p v3 + +unset v1 v2 v3 + +declare -A v1=( "$foo" $bar ) +declare -p v1 + +declare -A v2=( ["$foo"]=$bar ) +declare -p v2 + +declare -A v3 +v3=( "$foo" $bar ) +declare -p v3 + +unset v1 v2 v3 + +declare -A v1=( "$foo" "$bar" ) +declare -p v1 + +declare -A v2=( ["$foo"]="$bar" ) +declare -p v2 + +declare -A v3 +v3=( "$foo" "$bar" ) +declare -p v3 + +v1+=( $xtra xtra ) +v2+=( "$xtra" xtra ) +v3+=( '$xtra' xtra ) + +declare -p v1 v2 v3 + +v1+=( [$xtra]='new xtra' ) +v2+=( ["$xtra"]='new xtra' ) +v3+=( ['$xtra']='new xtra' ) + +declare -p v1 v2 v3 diff --git a/tests/assoc13.sub b/tests/assoc13.sub new file mode 100644 index 00000000..7e669727 --- /dev/null +++ b/tests/assoc13.sub @@ -0,0 +1,44 @@ +# assignment to @ and * + +declare -A assoc +key=@ +key2=* + +assoc[$key]=at +assoc[$key2]=star +assoc[!]=bang +declare -p assoc + +echo ${assoc[$key]} +echo ${assoc[$key2]} +unset assoc + +declare -A a + +a[@]=at +declare -p a + +declare -a ia +ia[@]=garbage + +declare -p ia + +declare a[@]=at2 +declare -p a + +unset a ia + +declare -A a +printf -v a[@] "%10s" string + +declare -p a +unset a + +declare -A a +declare a[$key2]=star +declare a[@]=at +declare a[*]=star2 + +declare -p a +unset a + diff --git a/tests/assoc14.sub b/tests/assoc14.sub new file mode 100644 index 00000000..95df0492 --- /dev/null +++ b/tests/assoc14.sub @@ -0,0 +1,35 @@ +# 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 <http://www.gnu.org/licenses/>. +# + +declare -A assoc=(hello world "key with spaces" "value with spaces" one 1 foo bar) +declare -p assoc + +recho "${assoc[@]}" +recho "${assoc[@]@k}" + +recho "${assoc[*]}" +recho "${assoc[*]@k}" + +set -- hello world "key with spaces" "value with spaces" one 1 foo bar +recho "${@}" +recho "${@@K}" +recho "${@@k}" + +declare -A clone +eval clone=\( "${assoc[@]@K}" \) +declare -p clone + +declare -A posparams +eval posparams=\( "${@@K}" \) +declare -p posparams diff --git a/tests/assoc15.sub b/tests/assoc15.sub new file mode 100644 index 00000000..c47b1535 --- /dev/null +++ b/tests/assoc15.sub @@ -0,0 +1,92 @@ +# 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 <http://www.gnu.org/licenses/>. +# + +# associative arrays first + +v=$'\x01' + +declare -A var foo v2 +var=( $'\x01' $'\x01\x01\x01\x01' ) +declare -p var +v2=( $v $v$v$v$v ) +declare -p v2 + +recho "${var[@]@k}" +eval foo=\( "${var[@]@k}" \) +declare -p foo + +var=( ) +declare -p var + +recho "${var[@]@k}" +eval foo=\( "${var[@]@k}" \) +declare -p foo + +var=( []= ) +declare -p var + +recho "${var[@]@k}" +eval foo=\( "${var[@]@k}" \) +declare -p foo + +# now indexed arrays +unset -v var foo + +declare -a var +var=( [0]= ) +declare -p var + +declare -a foo +recho "${var[@]@Q}" +eval foo=\( "${var[@]@Q}" \) +declare -p foo + +var=( ) +declare -p var + +unset foo + +declare -a foo +recho "${var[@]@Q}" +eval foo=\( "${var[@]@Q}" \) +declare -p foo + +# similar to array29.sub +unset -v var foo v2 + +declare -A var +var=( one $'\x01\x01\x01\x01' two ab$'\001'cd ) +declare -p var + +pv() +{ + local -A foo + eval foo=\( "${var[@]@k}" \) + declare -p foo +} +pv + +pv1() +{ + local -A foo=( $'\x01' "${var[two]}" ) + declare -p foo +} +pv1 + +pv2() +{ + local -A foo=( [$'\x01']="${var[one]}" ) + declare -p foo +} +pv2 diff --git a/tests/assoc16.sub b/tests/assoc16.sub new file mode 100644 index 00000000..ae8296b3 --- /dev/null +++ b/tests/assoc16.sub @@ -0,0 +1,56 @@ +# 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 <http://www.gnu.org/licenses/>. +# + +# bash versions up to and including bash-5.1 expanded these subscripts more +# than once + +declare -A A + +A["Darwin"]=darjeeling +A['$(echo Darwin ; echo stderr>&2)']=darjeeling + +declare -p A + +echo ${A[$(echo Darwin ; echo stderr>&2)]//eel/shark} +echo ${A['$(echo Darwin ; echo stderr>&2)']//eel/shark} + +echo ${A[$(echo Darwin ; echo stderr>&2)]:0:4} +echo ${A['$(echo Darwin ; echo stderr>&2)']:0:4} + +echo ${A[$(echo Darwin ; echo stderr>&2)]^^} +echo ${A['$(echo Darwin ; echo stderr>&2)']^^} + +echo ${A[$(echo Darwin ; echo stderr>&2)]@Q} +echo ${A['$(echo Darwin ; echo stderr>&2)']@Q} + +echo ${A[$(echo Darwin ; echo stderr>&2)]%ing} +echo ${A['$(echo Darwin ; echo stderr>&2)']%ing} + +echo ${#A[$(echo Darwin ; echo stderr>&2)]} +echo ${#A['$(echo Darwin ; echo stderr>&2)']} + +echo ${A[$(echo Darwin ; echo stderr>&2)]:-value} +echo ${A['$(echo Darwin ; echo stderr>&2)']:-value} + +echo ${A[$(echo Darwin ; echo stderr>&2)]:+set} +echo ${A['$(echo Darwin ; echo stderr>&2)']:+set} + +echo ${A[$(echo Darwin ; echo stderr>&2)]:+set} +echo ${A['$(echo Darwin ; echo stderr>&2)']:+set} + +darjeeling=7*6 +Darwin=7*4 + +echo $(( ${A[$(echo Darwin ; echo stderr>&2)]} )) +echo $(( ${A['$(echo Darwin ; echo stderr>&2)']} )) diff --git a/tests/assoc17.sub b/tests/assoc17.sub new file mode 100644 index 00000000..a98aaa15 --- /dev/null +++ b/tests/assoc17.sub @@ -0,0 +1,58 @@ +# 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 <http://www.gnu.org/licenses/>. +# +# test behavior with `unset' and `[' and ']' subscripts + +declare -A A +rkey=']' +lkey='[' + +A[$rkey]=rbracket +A[$lkey]=lbracket +declare -p A + +unset A[$rkey] +unset A[$lkey] +declare -p A + +A["$rkey"]=rbracket +A["$lkey"]=lbracket +declare -p A + +unset A["$rkey"] +unset A["$lkey"] +declare -p A + +A[\]]=rbracket +A[\[]=lbracket +declare -p A + +unset A[\]] +unset A[\[] +declare -p A + +A[']']=rbracket +A['[']=lbracket +declare -p A + +unset A[']'] +unset A['['] +declare -p A + +A["]"]=rbracket +A["["]=lbracket +declare -p A + +unset A["]"] +unset A["["] +declare -p A diff --git a/tests/assoc18.sub b/tests/assoc18.sub new file mode 100644 index 00000000..05976093 --- /dev/null +++ b/tests/assoc18.sub @@ -0,0 +1,59 @@ +# 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 <http://www.gnu.org/licenses/>. +# + +# test behavior of builtins that can take array subscript arguments, make +# sure they work in the presence of associative arrays and `problematic' keys +# if assoc_expand_once is set +# +# affected builtins: printf, read, wait + +declare -A A +rkey=']' +lkey='[' + +shopt -s assoc_expand_once + +printf -v A[$rkey] rbracket +printf -v A[$lkey] lbracket +declare -p A + +unset A[$rkey] +unset A[$lkey] +declare -p A + +unset A +declare -A A + +read A[$rkey] <<<rbracket +read A[$lkey] <<<lbracket +declare -p A + +unset A[$rkey] +unset A[$lkey] +declare -p A + +unset A +declare -A A + +{ sleep 1 ; exit 4; } & +{ sleep 2 ; exit 5; } & bgpid1=$! +{ sleep 4 ; exit 6; } & + +wait -p A[$rkey] -n %2 %3 +case "${A[$rkey]}" in +$bgpid1) echo $?: ok 1;; +*) echo bad 1;; +esac + +exit 0 diff --git a/tests/assoc9.sub b/tests/assoc9.sub index b8867187..f83ac6d5 100644 --- a/tests/assoc9.sub +++ b/tests/assoc9.sub @@ -128,3 +128,32 @@ aa[$key]=foo echo "${aa[$key]}" [[ -v aa[$key] ]] || echo bad assoc expansion + +shopt -u assoc_expand_once + +declare -A assoc + +var=x123 +assoc['$var']=value + +declare -p assoc + +unset "assoc[$var]" +declare -p assoc + +unset 'assoc[$var]' +declare -p assoc + +shopt -s assoc_expand_once +unset 'assoc[$var]' +declare -p assoc + +typeset -A foo + +foo["foo]bar"]=bip +typeset foo["foo]bar"]=bax + +echo ${!foo[@]} +echo ${foo[@]} + +declare -p foo diff --git a/tests/builtins.right b/tests/builtins.right index 832472f6..4f51d436 100644 --- a/tests/builtins.right +++ b/tests/builtins.right @@ -1,3 +1,4 @@ +1000 a end-1 a @@ -144,11 +145,11 @@ AVAR foo declare -x foo="" declare -x FOO="\$\$" -./builtins.tests: line 226: declare: FOO: not found +./builtins.tests: line 228: declare: FOO: not found declare -x FOO="\$\$" ok ok -./builtins.tests: line 258: kill: 4096: invalid signal specification +./builtins.tests: line 260: kill: 4096: invalid signal specification 1 a\n\n\nb a @@ -178,10 +179,16 @@ unset2 1 1 1 +0 +0 +assoc A unset +array a assoc A array a assoc B unset array b unset +assoc B unset +array b unset scalar 1 scalar 2 scalar 3 unset @@ -271,4 +278,4 @@ type + command -p -- command -v type type + set +x -./builtins.tests: line 282: exit: status: numeric argument required +./builtins.tests: line 284: exit: status: numeric argument required diff --git a/tests/builtins.tests b/tests/builtins.tests index 00ebc0fd..8eee43e6 100644 --- a/tests/builtins.tests +++ b/tests/builtins.tests @@ -15,7 +15,9 @@ set +p set +o posix -ulimit -c 0 2>/dev/null +ulimit -S -c 0 2>/dev/null +ulimit -c -S -- 1000 2>/dev/null +ulimit -c 2>/dev/null # check that break breaks loops for i in a b c; do echo $i; break; echo bad-$i; done diff --git a/tests/builtins5.sub b/tests/builtins5.sub index d36e03a5..4fcf793d 100644 --- a/tests/builtins5.sub +++ b/tests/builtins5.sub @@ -36,15 +36,25 @@ echo ${#a[@]} typeset -A B typeset -a b +echo ${#B[@]} +echo ${#b[@]} + scalar1=foo scalar2= +# this now checks for A[@] treating @ as a valid key - post-bash-5.1 if [ -v A[@] ]; then echo assoc A; else echo assoc A unset; fi if [ -v a[@] ]; then echo array a; else echo array a unset; fi +if [ ${#A[@]} -gt 0 ]; then echo assoc A; else echo assoc A unset; fi +if [ ${#a[@]} -gt 0 ]; then echo array a; else echo array a unset; fi + if [ -v B[@] ]; then echo assoc B; else echo assoc B unset; fi if [ -v b[@] ]; then echo array b; else echo array b unset; fi +if [ ${#B[@]} -gt 0 ]; then echo assoc B; else echo assoc B unset; fi +if [ ${#b[@]} -gt 0 ]; then echo array b; else echo array b unset; fi + if [ -v scalar1[@] ]; then echo scalar 1; else echo scalar 1 unset; fi if [ -v scalar2[@] ]; then echo scalar 2; else echo scalar 2 unset; fi if [ -v scalar3[@] ]; then echo scalar 3; else echo scalar 3 unset; fi @@ -71,4 +81,3 @@ echo scalar: ${#scalar3} echo scalar: ${#scalar3[@]} - diff --git a/tests/case.right b/tests/case.right index 557bcadf..d33c8c5a 100644 --- a/tests/case.right +++ b/tests/case.right @@ -14,6 +14,7 @@ no no no ok +esac ok 1 ok 2 ok 3 diff --git a/tests/case.tests b/tests/case.tests index 2ffcb906..7ad4c683 100644 --- a/tests/case.tests +++ b/tests/case.tests @@ -62,6 +62,10 @@ case abc in (["$empty"]|[!a-z]*) echo yes ;; (*) echo no ;; esac case " " in ( [" "] ) echo ok;; ( * ) echo no;; esac +# posix issue discovered after bash-5.1 was released +case esac in (esac) echo esac;; esac +case k in else|done|time|esac) for f in 1 2 3 ; do :; done esac + # tests of quote removal and pattern matching ${THIS_SH} ./case1.sub ${THIS_SH} ./case2.sub diff --git a/tests/complete.right b/tests/complete.right index 5bc89a05..c8bf1dc0 100644 --- a/tests/complete.right +++ b/tests/complete.right @@ -1,41 +1,49 @@ complete -f -X '!*.+(ps|PS)' gs -complete -c nice complete -e printenv -complete -c gdb complete -f -X '!*.texi*' texi2html -complete -j -P '%' fg complete -g groupmod -complete -f -X '!*.dvi' dvips -complete -f -X '!*.texi*' texi2dvi complete -v -S '=' typeset -complete -f . complete -c nohup complete -a unalias complete -g groupdel complete -A hostname telnet -complete -v -S '=' declare -complete -v -S '=' export complete -v -S '=' local complete -v -S '=' readonly complete -o bashdefault -o filenames -o nospace -F _comp_cd cd -complete -f -X '!*.dvi' xdvi complete -c type complete -f ln complete -f -X '!*.+(gz|tgz)' gunzip complete -f -X '!*.texi*' makeinfo -complete -u su complete -j -P '%' jobs -complete -o dirnames -o filenames -o nospace -d popd -complete -A signal trap complete -o dirnames -o filenames -o nospace -d pushd complete -f -X '!*.pdf' acroread complete -v unset complete -f -X '!*.+(ps|PS)' ghostview -complete -j -W '$(ps -x | tail +2 | cut -c1-5)' -P '%' wait complete -A hostname rsh complete -c exec -complete -f -X '!*.Z' zmore complete -A signal kill +complete -c eval +complete -f chown +complete -f gzip +complete -W '"${GROUPS[@]}"' newgrp +complete -A shopt shopt +complete -A hostname ftp +complete -A hostname rlogin +complete -v getopts +complete -c nice +complete -c gdb +complete -j -P '%' fg +complete -f -X '!*.dvi' dvips +complete -f -X '!*.texi*' texi2dvi +complete -f . +complete -v -S '=' declare +complete -v -S '=' export +complete -f -X '!*.dvi' xdvi +complete -u su +complete -o dirnames -o filenames -o nospace -d popd +complete -A signal trap +complete -j -W '$(ps -x | tail +2 | cut -c1-5)' -P '%' wait +complete -f -X '!*.Z' zmore complete -j -P '%' disown complete -f -X '!*.+(ps|PS)' gs complete -f -X '!*.+(ps|PS)' gv @@ -45,19 +53,11 @@ complete -A stopped -P '%' bg complete -f cat complete -d mkdir complete -A helptopic help -complete -c eval -complete -f chown complete -v read complete -c -k time complete -f -X '!*.Z' zcat -complete -f gzip -complete -W '"${GROUPS[@]}"' newgrp complete -f -X '!*.Z' uncompress complete -d rmdir -complete -A shopt shopt -complete -A hostname ftp complete -f more -complete -A hostname rlogin -complete -v getopts complete -f -X '!*.+(gz|tgz)' gzcat ./complete.tests: line 123: complete: notthere: no completion specification diff --git a/tests/comsub-eof.right b/tests/comsub-eof.right index 42677985..cd5ab692 100644 --- a/tests/comsub-eof.right +++ b/tests/comsub-eof.right @@ -1,15 +1,17 @@ -./comsub-eof0.sub: line 1: unexpected EOF while looking for matching `)' -./comsub-eof0.sub: line 5: syntax error: unexpected end of file +./comsub-eof0.sub: line 5: warning: here-document at line 3 delimited by end-of-file (wanted `EOF') +hi hi ./comsub-eof2.sub: line 2: warning: here-document at line 1 delimited by end-of-file (wanted `EOF') hi -./comsub-eof3.sub: line 1: unexpected EOF while looking for matching `)' -./comsub-eof3.sub: line 5: syntax error: unexpected end of file -./comsub-eof4.sub: line 6: warning: here-document at line 4 delimited by end-of-file (wanted `EOF') +./comsub-eof3.sub: line 4: warning: here-document at line 1 delimited by end-of-file (wanted `EOF') +./comsub-eof3.sub: line 5: unexpected EOF while looking for matching `)' +./comsub-eof4.sub: line 3: warning: here-document at line 1 delimited by end-of-file (wanted `EOF') contents -./comsub-eof5.sub: line 8: warning: here-document at line 6 delimited by end-of-file (wanted `)') +./comsub-eof5.sub: line 4: warning: here-document at line 2 delimited by end-of-file (wanted `)') +hi +./comsub-eof5.sub: line 9: warning: here-document at line 7 delimited by end-of-file (wanted `EOF') hi -./comsub-eof5.sub: line 13: warning: here-document at line 11 delimited by end-of-file (wanted `EOF') +./comsub-eof5.sub: line 15: warning: here-document at line 13 delimited by end-of-file (wanted `)') hi -./comsub-eof6.sub: line 1: unexpected EOF while looking for matching `)' +./comsub-eof6.sub: command substitution: line 3: unexpected EOF while looking for matching `)' diff --git a/tests/comsub-eof0.sub b/tests/comsub-eof0.sub index 7b0775fb..7490faab 100644 --- a/tests/comsub-eof0.sub +++ b/tests/comsub-eof0.sub @@ -1,3 +1,5 @@ +# it's only the space before the paren that makes this an error +# when I fix it, it will show up here foo=$(cat <<EOF hi EOF ) diff --git a/tests/comsub-eof5.sub b/tests/comsub-eof5.sub index 3da9107e..4bada675 100644 --- a/tests/comsub-eof5.sub +++ b/tests/comsub-eof5.sub @@ -7,3 +7,9 @@ echo $( cat <<\EOF hi EOF) + +# this is currently an error; if I fix it it will show up here +echo "$( +cat <<\) +hi +))" diff --git a/tests/comsub-posix.right b/tests/comsub-posix.right index 9aebb848..037f0ed2 100644 --- a/tests/comsub-posix.right +++ b/tests/comsub-posix.right @@ -5,11 +5,14 @@ ab abcd abcd +mnop +qrst sh_352.26ax sh_352.26ay sh_352.25a sh_352.25b sh_352.27 ) ) ) abc +def here doc with ) ) bad' syntax @@ -56,9 +59,8 @@ here-doc with \() here-doc terminated with a parenthesis ' # or a single back- or doublequote line terminated with a backslash -./comsub-posix1.sub: command substitution: line 2: syntax error near unexpected token `)' -./comsub-posix1.sub: command substitution: line 2: ` if x; then echo foo )' -after +./comsub-posix1.sub: line 1: syntax error near unexpected token `)' +./comsub-posix1.sub: line 1: `echo $( if x; then echo foo )' swap32_posix is a function swap32_posix () { @@ -74,5 +76,25 @@ swap32_posix () )); done } +bash: -c: line 1: syntax error near unexpected token `done' +bash: -c: line 1: `: $(case x in x) ;; x) done esac)' +bash: -c: line 1: syntax error near unexpected token `done' +bash: -c: line 1: `: $(case x in x) ;; x) done ;; esac)' +bash: -c: line 1: syntax error near unexpected token `esac' +bash: -c: line 1: `: $(case x in x) (esac) esac)' +bash: -c: line 1: syntax error near unexpected token `in' +bash: -c: line 1: `: $(case x in esac|in) foo;; esac)' +bash: -c: line 1: syntax error near unexpected token `done' +bash: -c: line 1: `: $(case x in x) ;; x) done)' +case: -c: line 3: syntax error near unexpected token `esac' +case: -c: line 3: `$( esac ; bar=foo ; echo "$bar")) echo bad 2;;' +ok 2 +inside outside +ok 3 +syntax-error: -c: line 2: syntax error near unexpected token `done' +syntax-error: -c: line 2: `: $(case x in x) ;; x) done ;; esac)' yes + + + ab cde diff --git a/tests/comsub-posix.tests b/tests/comsub-posix.tests index 4fe1dfaa..ab7cd295 100644 --- a/tests/comsub-posix.tests +++ b/tests/comsub-posix.tests @@ -28,6 +28,11 @@ echo $( echo $() echo ab$()cd echo ab$( )cd +echo mn$( +)op +echo qr$( + + )st echo $(case a in (a) echo sh_352.26ax; esac ) echo $(case a in (a) echo sh_352.26ay; esac) @@ -42,6 +47,9 @@ echo $( echo abc # a comment with ) ) +echo $(#a comment with ) +echo def) + echo $( cat <<eof here doc with ) @@ -226,11 +234,13 @@ echo $( ) ${THIS_SH} ./comsub-posix1.sub - ${THIS_SH} ./comsub-posix2.sub - ${THIS_SH} ./comsub-posix3.sub +#${THIS_SH} ./comsub-posix4.sub +${THIS_SH} ./comsub-posix5.sub +${THIS_SH} ./comsub-posix6.sub + # produced a parse error through bash-4.0-beta2 : $(echo foo)" " @@ -247,6 +257,12 @@ unset x : $(case a in a) echo ;; # comment esac) +: $(case a in + a) + echo + ;; # comment +esac) + # fixed after bash-4.3 released testing=$( echo test | while read line; do @@ -257,5 +273,14 @@ testing=$( done ) +# sanity check for empty comsubs +echo $() +echo $( +) + +echo $( + + ) + # recommended to be parsed as a nested comsub instead of arithsub echo $(( echo ab cde ) ) diff --git a/tests/comsub-posix1.sub b/tests/comsub-posix1.sub index bbcc60fb..de6f473a 100644 --- a/tests/comsub-posix1.sub +++ b/tests/comsub-posix1.sub @@ -1,3 +1,3 @@ echo $( if x; then echo foo ) -echo after +echo should not see this diff --git a/tests/comsub-posix5.sub b/tests/comsub-posix5.sub new file mode 100644 index 00000000..f10e773a --- /dev/null +++ b/tests/comsub-posix5.sub @@ -0,0 +1,70 @@ +# 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 <http://www.gnu.org/licenses/>. +# +: ${THIS_SH:=./bash} + +# problems with recognzing `esac' after a right paren in a command substitution + +: $(case x in x) esac) +: $(case x in x) ;; x) esac) +# non-reserved word beginning with e +: $(case x in x) ;; x) echo ;; esac) +# reserved word beginning with e +: $(case x in x) ;; x) eval esac ;; esac) + +: $(case x in x ) esac) +: $(case x in x ) ;; x) esac) + +: $(case x in (x) esac) +: $(case x in (x) ;; (x) esac) +: $(case x in (x) ;; x) esac) +: $(case x in (x) (echo a) esac) + +: $(case x in (x) (echo esac) esac) +: $(case x in x) (echo esac) esac) + +# these errors should be caught sooner +${THIS_SH} -c ': $(case x in x) ;; x) done esac)' bash +${THIS_SH} -c ': $(case x in x) ;; x) done ;; esac)' bash +${THIS_SH} -c ': $(case x in x) (esac) esac)' bash + +# these are not errors +: $(case x in x) ;; x) eval done ;; esac) + +# these are just ridiculous +: $(case x in (x) a() { echo a; } esac) +: $(case x in (x) if :; then echo a; fi esac) +: $(case x in (x) { echo a; } esac) +: $(case x in (x) while false; do echo a; done esac) +: $(case x in (x) case y in (y) echo a;; esac esac) +: $(case x in (x) case y in (y) echo a;; esac ;; (y) foo ;; esac) + +: $(case x in x) a() { echo a; } esac) +: $(case x in x) if :; then echo a; fi esac) +: $(case x in x) { echo a; } esac) +: $(case x in x) while false; do echo a; done esac) +: $(case x in x) case y in (y) echo a;; esac esac) +: $(case x in x) case y in (y) echo a;; esac ;; y) foo ;; esac) +: $(case x in x) case y in y) echo a;; esac ;; y) foo ;; esac) + +: $(case ni in esac) +: $(case in in esac) + +: $(case x in in|esac) foo;; esac) +: $(case esac in (esac) echo esac;; esac) +: $(case k in else|done|time|esac) for f in 1 2 3 ; do :; done esac) + +# this is an error +${THIS_SH} -c ': $(case x in esac|in) foo;; esac)' bash + +${THIS_SH} -c ': $(case x in x) ;; x) done)' bash diff --git a/tests/comsub-posix6.sub b/tests/comsub-posix6.sub new file mode 100644 index 00000000..212ad204 --- /dev/null +++ b/tests/comsub-posix6.sub @@ -0,0 +1,43 @@ +: ${THIS_SH:=./bash} + +# comsub should not inherit PST_COMPASSIGN + +C=($(echo "${A[@]}" | \ + (while read -d ' ' i; do + C=(${C/ ${i%% *} / }) + done + echo ${C[@]}))) + +# comsub should not inherit PST_CASEPAT + +${THIS_SH} -c ' +case foo in +$( esac ; bar=foo ; echo "$bar")) echo bad 2;; +*) echo ok 2;; +esac + +echo we should not see this' case + +# comsub should not inherit PST_SUBSHELL + +${THIS_SH} -c '( case foo in + ( $(echo foo | cat )) echo ok 2;; + *) echo bad 2;; + esac + + echo $( echo inside ) outside )' subshell + +# comsub should not inherit PST_REDIRLIST + +${THIS_SH} -c ' +{fd}</dev/null {fd2}<$(foo=/dev/null ; echo $foo) exec +case $fd2 in +[0-9]*) echo ok 3 ;; +*) echo bad 3 ;; +esac' redirlist + +# comsub should exit on syntax error while parsing +${THIS_SH} -c ' +: $(case x in x) ;; x) done ;; esac) + +echo after syntax error' syntax-error diff --git a/tests/comsub.right b/tests/comsub.right index a329c832..eae8c3b2 100644 --- a/tests/comsub.right +++ b/tests/comsub.right @@ -19,6 +19,7 @@ argv[1] = <sed> argv[2] = <-e> argv[3] = <s/[^I:]//g> argv[1] = <foo\^Jbar> argv[1] = <foobar> argv[1] = <foo\^Jbar> +nested #esac a ok 1 @@ -55,3 +56,24 @@ d \ g d \ g +ok 1 +ok 2 +ok 3 +ok 4 +ok 5 +ok 6 +ok 7 +ok 9 +ok 8 +ok 8 +Mon Aug 29 20:03:02 EDT 2022 +post foo +Mon Aug 29 20:03:02 EDT 2022 +post foo1 +Mon Aug 29 20:03:02 EDT 2022 +Mon Aug 29 20:03:02 EDT 2022 after +7 +Mon Aug 29 20:03:02 EDT 2022 +hey after x +./comsub6.sub: line 40: syntax error near unexpected token `)' +./comsub6.sub: line 40: `math1)' diff --git a/tests/comsub.tests b/tests/comsub.tests index 47863024..698ce30b 100644 --- a/tests/comsub.tests +++ b/tests/comsub.tests @@ -69,7 +69,16 @@ comsub_foo_1() echo $(while true; do case $HOME in /*) echo abs ;; esac; done) } +echo $( +echo $( +echo $(echo $( echo nested ) +) +) +) + ${THIS_SH} ./comsub1.sub ${THIS_SH} ./comsub2.sub ${THIS_SH} ./comsub3.sub ${THIS_SH} ./comsub4.sub +${THIS_SH} ./comsub5.sub +${THIS_SH} ./comsub6.sub diff --git a/tests/comsub5.sub b/tests/comsub5.sub new file mode 100644 index 00000000..cc83374c --- /dev/null +++ b/tests/comsub5.sub @@ -0,0 +1,51 @@ +# 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 <http://www.gnu.org/licenses/>. +# + +# this is a new feature: expanding aliases when initially parsing command +# substitutions. required by posix, so enabled in posix mode. default mode +# stays backwards compatible. + +shopt -s expand_aliases +set -o posix + +alias switch=case + +switch foo in foo) echo ok 1;; esac + +echo $( switch foo in foo) echo ok 2;; esac ) +echo "$( switch foo in foo) echo ok 3;; esac )" + +echo $( switch foo in (foo) echo ok 4;; esac ) +echo "$( switch foo in (foo) echo ok 5;; esac )" + +alias nest='(' + +echo $( nest echo ok 6 ) ) +echo "$( nest echo ok 7 ) )" + +alias short='echo ok 8 )' + +alias DO='{ ' +alias DONE='}' +got=$(DO +echo ok 9; DONE) +echo "$got" + +echo $( short +echo "$( short " + +# remember that short" won't work because you start a new quoting context +# inside $( and the token (`short') won't be delimited by the ending double +# quote, so there's no opportunity to perform the alias expansion that would +# terminate the command substitution diff --git a/tests/comsub6.sub b/tests/comsub6.sub new file mode 100644 index 00000000..d2b02bf4 --- /dev/null +++ b/tests/comsub6.sub @@ -0,0 +1,40 @@ +# 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 <http://www.gnu.org/licenses/>. +# +DATE='Mon Aug 29 20:03:02 EDT 2022' +shopt -s expand_aliases + +alias foo='echo $(echo $DATE)' +alias foo1='echo $(echo $DATE) ' + +foo +echo post foo + +foo1 +echo post foo1 + +alias comsub0='echo $(echo $DATE' +comsub0) +comsub0 ) after + +alias math0='echo $(( 4+3 )' +math0) + +alias x='VAR=$(echo hey)' +x +foo + +echo $VAR after x + +alias math1='echo $( date )' +math1) diff --git a/tests/cond.right b/tests/cond.right index 59a4a886..a72a1537 100644 --- a/tests/cond.right +++ b/tests/cond.right @@ -2,6 +2,10 @@ returns: 0 returns: 0 returns: 1 returns: 0 +1 +0 +1 +0 returns: 0 returns: 0 returns: 0 @@ -23,10 +27,12 @@ returns: 0 returns: 1 returns: 1 returns: 0 -./cond.tests: line 114: [[: 4+: syntax error: operand expected (error token is "+") +./cond.tests: line 122: [[: 4+: syntax error: operand expected (error token is "+") returns: 1 returns: 0 returns: 0 +returns: 0 +returns: 0 returns: 1 returns: 0 returns: 0 diff --git a/tests/cond.tests b/tests/cond.tests index aa6a8104..c0747e98 100644 --- a/tests/cond.tests +++ b/tests/cond.tests @@ -33,6 +33,14 @@ echo returns: $? [[ ! x || x ]] echo returns: $? +# ! toggles on and off rather than just setting an `invert result' flag +# this differs from ksh93 +[[ ! 1 -eq 1 ]]; echo $? +[[ ! ! 1 -eq 1 ]]; echo $? + +[[ ! ! ! 1 -eq 1 ]]; echo $? +[[ ! ! ! ! 1 -eq 1 ]]; echo $? + # parenthesized terms didn't work right until post-2.04 [[ a ]] echo returns: $? @@ -122,6 +130,13 @@ A=7 [[ $IVAR -eq A ]] echo returns: $? +[[ "$IVAR" -eq "7" ]] +echo returns: $? + +A=7 +[[ "$IVAR" -eq "A" ]] +echo returns: $? + unset IVAR A # more pattern matching tests @@ -207,6 +222,9 @@ del=$'\177' [[ "" == "$foo" ]] && echo ok 4 [[ "$del" == "${foo,,}" ]] || echo ok 5 +# allow reserved words after a conditional command just because +if [[ str ]] then [[ str ]] fi + ${THIS_SH} ./cond-regexp1.sub ${THIS_SH} ./cond-regexp2.sub diff --git a/tests/cprint.right b/tests/cprint.right index 20000724..269136dc 100644 --- a/tests/cprint.right +++ b/tests/cprint.right @@ -19,7 +19,7 @@ tf () i=$(( i + 1 )); done; [[ -r /dev/fd/0 && -w /dev/fd/1 ]] || echo oops > /dev/null; - for name in $( echo 1 2 3 ); + for name in $(echo 1 2 3); do test -r /dev/fd/$name; done; diff --git a/tests/dollar-at-star b/tests/dollar-at-star index d4808989..721eea12 100755..100644 --- a/tests/dollar-at-star +++ b/tests/dollar-at-star @@ -1,3 +1,17 @@ +# 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 <http://www.gnu.org/licenses/>. +# + # first, let's start with the basics recho "$@" @@ -246,6 +260,11 @@ ${THIS_SH} ./dollar-at-star8.sub # with different values for IFS ${THIS_SH} ./dollar-at-star9.sub +# tests for expansions of "$*" and "$@" and their array equivalents when $1 == '' +# and we're using the POSIX word expansions +${THIS_SH} ./dollar-at-star10.sub +${THIS_SH} ./dollar-at-star11.sub + # tests for special expansion of "$*" and "${array[*]}" when used with other # expansions -- bugs through bash-2.05b ${THIS_SH} ./dollar-star1.sub diff --git a/tests/dollar-at-star10.sub b/tests/dollar-at-star10.sub new file mode 100644 index 00000000..6b52b015 --- /dev/null +++ b/tests/dollar-at-star10.sub @@ -0,0 +1,66 @@ +# checks for array variables and positional parameter expansions losing quoted +# null string expansions -- problem through bash-5.1 + +set -- '' +myvar[0]= +a="${myvar[*]}" + +recho "$*" +recho "${*}" + +recho "${a}" +recho "${myvar[*]}" + +recho "${a:+nonnull}" +recho "${myvar[*]:+nonnull}" + +a="${myvar[@]}" + +recho "$@" +recho "${@}" + +recho "${a}" +recho "${myvar[@]}" + +recho "${a:+nonnull}" +recho "${myvar[@]:+nonnull}" + +# check to make sure literal CTLNULs are handled correctly +set -- $'\x7f' + +recho "$@" +recho "${@}" +recho "${@:+nonnull}" + +recho "$*" +recho "${*}" +recho "${*:+nonnull}" + +shift $# + +# these should echo nothing +recho "${@}" +recho "${@:+nonnull}" + +unset -v a + +# make sure that other null expansions result in null strings where appropriate +set -- '' +a[0]= + +recho "$*"$x +recho "${*}"$x + +recho "$@"$x +recho "${@}"$x + +recho "${a[*]}"$x +recho "${a[@]}"$x + + +recho "$@"$x +recho "${@}"$x + +recho "${a[*]}" +recho "${a[@]}" + diff --git a/tests/dollar-at-star11.sub b/tests/dollar-at-star11.sub new file mode 100644 index 00000000..b7a6ec46 --- /dev/null +++ b/tests/dollar-at-star11.sub @@ -0,0 +1,80 @@ +a[0]='/' +set -- / + +# these should all result in the empty (null) string + +recho "${a[0]%?}" +recho "${a[*]%?}" +recho "${a[@]%?}" + +recho "${*%?}" +recho "${@%?}" + +recho "${a[0]#?}" +recho "${a[*]#?}" +recho "${a[@]#?}" + +recho "${*#?}" +recho "${@#?}" + +recho "${a[0]/\//}" +recho "${a[*]/\//}" +recho "${a[@]/\//}" + +recho "${*/\//}" +recho "${@/\//}" + +recho "${a[0]:1:1}" +# these next four will all echo / + +# arrays are zero-based +recho "${a[*]:0:1}" +recho "${a[@]:0:1}" +# but the positional parameters start at 1 +recho "${*:1:1}" +recho "${@:1:1}" + +a[0]='' +set -- '' + +# arrays are zero-based +recho "${a[*]:0:1}" +recho "${a[@]:0:1}" + +recho "${*:1:1}" +recho "${@:1:1}" + +# these should all result in the empty (null) string, or quoted as such + +recho "${a[0]@Q}" +recho "${a[*]@Q}" +recho "${a[@]@Q}" + +recho "${*@Q}" +recho "${@@Q}" + +recho "${a[0]@L}" +recho "${a[*]@L}" +recho "${a[@]@L}" + +recho "${*@L}" +recho "${@@L}" + +# examples from the bug report +unset -v a + +a[0]='/' +for i in "${a[@]%/}"; do recho "$i"; done + +a[0]='' +for i in "${a[@]}"; do recho "$i"; done + +a[0]='/' +a[1]="//" +for i in "${a[@]%/}"; do recho "$i"; done + +unset -v x y +x=('/') +y=("${x[@]%/}") + +echo "${#x[@]}:${#y[@]}" diff --git a/tests/dollar.right b/tests/dollar.right index 09910d7e..10c5cca1 100644 --- a/tests/dollar.right +++ b/tests/dollar.right @@ -399,6 +399,73 @@ argv[1] = <^?> argv[1] = <^?> argv[1] = <> argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <^?> +argv[1] = <^?> +argv[1] = <nonnull> +argv[1] = <^?> +argv[1] = <^?> +argv[1] = <nonnull> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = </> +argv[1] = </> +argv[1] = </> +argv[1] = </> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <''> +argv[1] = <''> +argv[1] = <''> +argv[1] = <''> +argv[1] = <''> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = </> +1:1 xa|xb|xc xa|xb|xc a|b|c diff --git a/tests/dynvar.tests b/tests/dynvar.tests index 5aefab64..ddf69ed1 100644 --- a/tests/dynvar.tests +++ b/tests/dynvar.tests @@ -50,15 +50,27 @@ unset before after # EPOCHSECONDS # not exact, but should work -# could also use python -c 'import time; ts = int(time.time()); print(ts)' -now1=$(perl -e 'print time') +# date +%s should be portable enough now +# then try gawk, perl, python in that order +now1=$(date +%s 2>/dev/null) D=date +[ -z "$now1" ] && +{ + now1=$(gawk 'BEGIN { print systime(); }' 2>/dev/null) D=gawk + [ -z "$now1" ] && now1=$(perl -e 'print time' 2>/dev/null) D=perl + [ -z "$now1" ] && now1=$(python -c 'import time; ts = int(time.time()); print(ts)' 2>/dev/null) D=python +} now2=$EPOCHSECONDS -case $now1 in -$now2) echo EPOCHSECONDS ok ;; -*) echo "current time via perl and EPOCHSECONDS possible mismatch|$now1|$now2" >&2 ;; -esac -unset now1 now2 +# use a window of +-1 second +offset=1 +if [[ -z $now1 ]]; then + echo "cannot get current time using date/gawk/perl/python" >&2 +elif (( $now1 - $offset <= $now2 && $now2 <= $now1 + $offset )); then + echo EPOCHSECONDS ok +else + echo "current time via $D and EPOCHSECONDS possible mismatch|$now1|$now2|offset=$offset" >&2 +fi +unset now1 now2 D LC_ALL=C # force decimal point to `.' now1=$EPOCHREALTIME diff --git a/tests/errors.right b/tests/errors.right index be0c8959..0bd88efb 100644 --- a/tests/errors.right +++ b/tests/errors.right @@ -11,93 +11,95 @@ declare -fr func unset: usage: unset [-f] [-v] [-n] [name ...] ./errors.tests: line 55: unset: func: cannot unset: readonly function ./errors.tests: line 58: declare: func: readonly function -./errors.tests: line 62: unset: XPATH: cannot unset: readonly variable -./errors.tests: line 68: unset: cannot simultaneously unset a function and a variable -./errors.tests: line 71: declare: -z: invalid option -declare: usage: declare [-aAfFgiIlnrtux] [-p] [name[=value] ...] -./errors.tests: line 73: declare: `-z': not a valid identifier -./errors.tests: line 74: declare: `/bin/sh': not a valid identifier -./errors.tests: line 78: declare: cannot use `-f' to make functions -./errors.tests: line 81: exec: -i: invalid option +./errors.tests: line 62: declare: -a: invalid option +./errors.tests: line 63: declare: -i: invalid option +./errors.tests: line 67: unset: XPATH: cannot unset: readonly variable +./errors.tests: line 73: unset: cannot simultaneously unset a function and a variable +./errors.tests: line 76: declare: -z: invalid option +declare: usage: declare [-aAfFgiIlnrtux] [name[=value] ...] or declare -p [-aAfFilnrtux] [name ...] +./errors.tests: line 78: declare: `-z': not a valid identifier +./errors.tests: line 79: declare: `/bin/sh': not a valid identifier +./errors.tests: line 83: declare: cannot use `-f' to make functions +./errors.tests: line 86: exec: -i: invalid option exec: usage: exec [-cl] [-a name] [command [argument ...]] [redirection ...] -./errors.tests: line 85: export: XPATH: not a function -./errors.tests: line 88: break: only meaningful in a `for', `while', or `until' loop -./errors.tests: line 89: continue: only meaningful in a `for', `while', or `until' loop -./errors.tests: line 92: shift: label: numeric argument required -./errors.tests: line 97: shift: too many arguments -./errors.tests: line 103: let: expression expected -./errors.tests: line 106: local: can only be used in a function -./errors.tests: line 109: logout: not login shell: use `exit' -./errors.tests: line 112: hash: notthere: not found -./errors.tests: line 115: hash: -v: invalid option +./errors.tests: line 90: export: XPATH: not a function +./errors.tests: line 93: break: only meaningful in a `for', `while', or `until' loop +./errors.tests: line 94: continue: only meaningful in a `for', `while', or `until' loop +./errors.tests: line 97: shift: label: numeric argument required +./errors.tests: line 102: shift: too many arguments +./errors.tests: line 108: let: expression expected +./errors.tests: line 111: local: can only be used in a function +./errors.tests: line 114: logout: not login shell: use `exit' +./errors.tests: line 117: hash: notthere: not found +./errors.tests: line 120: hash: -v: invalid option hash: usage: hash [-lr] [-p pathname] [-dt] [name ...] -./errors.tests: line 119: hash: hashing disabled -./errors.tests: line 122: export: `AA[4]': not a valid identifier -./errors.tests: line 123: readonly: `AA[4]': not a valid identifier -./errors.tests: line 126: unset: [-2]: bad array subscript -./errors.tests: line 130: AA: readonly variable -./errors.tests: line 134: AA: readonly variable -./errors.tests: line 142: shift: 5: shift count out of range -./errors.tests: line 143: shift: -2: shift count out of range -./errors.tests: line 146: shopt: no_such_option: invalid shell option name -./errors.tests: line 147: shopt: no_such_option: invalid shell option name -./errors.tests: line 150: umask: 09: octal number out of range -./errors.tests: line 151: umask: `:': invalid symbolic mode character -./errors.tests: line 152: umask: `:': invalid symbolic mode operator -./errors.tests: line 155: umask: -i: invalid option +./errors.tests: line 124: hash: hashing disabled +./errors.tests: line 127: export: `AA[4]': not a valid identifier +./errors.tests: line 128: readonly: `AA[4]': not a valid identifier +./errors.tests: line 131: unset: [-2]: bad array subscript +./errors.tests: line 135: AA: readonly variable +./errors.tests: line 139: AA: readonly variable +./errors.tests: line 147: shift: 5: shift count out of range +./errors.tests: line 148: shift: -2: shift count out of range +./errors.tests: line 151: shopt: no_such_option: invalid shell option name +./errors.tests: line 152: shopt: no_such_option: invalid shell option name +./errors.tests: line 155: umask: 09: octal number out of range +./errors.tests: line 156: umask: `:': invalid symbolic mode character +./errors.tests: line 157: umask: `:': invalid symbolic mode operator +./errors.tests: line 160: umask: -i: invalid option umask: usage: umask [-p] [-S] [mode] -./errors.tests: line 159: umask: `u': invalid symbolic mode character -./errors.tests: line 168: VAR: readonly variable -./errors.tests: line 171: declare: VAR: readonly variable -./errors.tests: line 172: declare: VAR: readonly variable -./errors.tests: line 174: declare: unset: not found -./errors.tests: line 177: VAR: readonly variable -./errors.tests: command substitution: line 181: syntax error near unexpected token `)' -./errors.tests: command substitution: line 181: ` for z in 1 2 3; do )' -./errors.tests: command substitution: line 182: syntax error near unexpected token `done' -./errors.tests: command substitution: line 182: ` for z in 1 2 3; done )' -./errors.tests: line 184: cd: HOME not set -./errors.tests: line 185: cd: /tmp/xyz.bash: No such file or directory -./errors.tests: line 187: cd: OLDPWD not set -./errors.tests: line 188: cd: /bin/sh: Not a directory -./errors.tests: line 190: cd: /tmp/cd-notthere: No such file or directory -./errors.tests: line 193: .: filename argument required +./errors.tests: line 164: umask: `u': invalid symbolic mode character +./errors.tests: line 173: VAR: readonly variable +./errors.tests: line 176: declare: VAR: readonly variable +./errors.tests: line 177: declare: VAR: readonly variable +./errors.tests: line 179: declare: unset: not found +./errors.tests: line 182: VAR: readonly variable +comsub: -c: line 1: syntax error near unexpected token `)' +comsub: -c: line 1: `: $( for z in 1 2 3; do )' +comsub: -c: line 1: syntax error near unexpected token `done' +comsub: -c: line 1: `: $( for z in 1 2 3; done )' +./errors.tests: line 189: cd: HOME not set +./errors.tests: line 190: cd: /tmp/xyz.bash: No such file or directory +./errors.tests: line 192: cd: OLDPWD not set +./errors.tests: line 193: cd: /bin/sh: Not a directory +./errors.tests: line 195: cd: /tmp/cd-notthere: No such file or directory +./errors.tests: line 198: .: filename argument required .: usage: . filename [arguments] -./errors.tests: line 194: source: filename argument required +./errors.tests: line 199: source: filename argument required source: usage: source filename [arguments] -./errors.tests: line 197: .: -i: invalid option +./errors.tests: line 202: .: -i: invalid option .: usage: . filename [arguments] -./errors.tests: line 200: set: -q: invalid option -set: usage: set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...] -./errors.tests: line 203: enable: sh: not a shell builtin -./errors.tests: line 203: enable: bash: not a shell builtin -./errors.tests: line 206: shopt: cannot set and unset shell options simultaneously -./errors.tests: line 209: read: var: invalid timeout specification -./errors.tests: line 212: read: `/bin/sh': not a valid identifier -./errors.tests: line 215: VAR: readonly variable -./errors.tests: line 218: readonly: -x: invalid option +./errors.tests: line 205: set: -q: invalid option +set: usage: set [-abefhkmnptuvxBCEHPT] [-o option-name] [--] [-] [arg ...] +./errors.tests: line 208: enable: sh: not a shell builtin +./errors.tests: line 208: enable: bash: not a shell builtin +./errors.tests: line 211: shopt: cannot set and unset shell options simultaneously +./errors.tests: line 214: read: var: invalid timeout specification +./errors.tests: line 217: read: `/bin/sh': not a valid identifier +./errors.tests: line 220: VAR: readonly variable +./errors.tests: line 223: readonly: -x: invalid option readonly: usage: readonly [-aAf] [name[=value] ...] or readonly -p -./errors.tests: line 221: eval: -i: invalid option +./errors.tests: line 226: eval: -i: invalid option eval: usage: eval [arg ...] -./errors.tests: line 222: command: -i: invalid option +./errors.tests: line 227: command: -i: invalid option command: usage: command [-pVv] command [arg ...] -./errors.tests: line 225: /bin/sh + 0: syntax error: operand expected (error token is "/bin/sh + 0") -./errors.tests: line 226: /bin/sh + 0: syntax error: operand expected (error token is "/bin/sh + 0") -./errors.tests: line 229: trap: NOSIG: invalid signal specification -./errors.tests: line 232: trap: -s: invalid option +./errors.tests: line 230: /bin/sh + 0: syntax error: operand expected (error token is "/bin/sh + 0") +./errors.tests: line 231: /bin/sh + 0: syntax error: operand expected (error token is "/bin/sh + 0") +./errors.tests: line 234: trap: NOSIG: invalid signal specification +./errors.tests: line 237: trap: -s: invalid option trap: usage: trap [-lp] [[arg] signal_spec ...] -./errors.tests: line 238: return: can only `return' from a function or sourced script -./errors.tests: line 242: break: 0: loop count out of range -./errors.tests: line 246: continue: 0: loop count out of range -./errors.tests: line 251: builtin: bash: not a shell builtin -./errors.tests: line 255: bg: no job control -./errors.tests: line 256: fg: no job control -./errors.tests: line 259: kill: -s: option requires an argument -./errors.tests: line 261: kill: S: invalid signal specification -./errors.tests: line 263: kill: `': not a pid or valid job spec +./errors.tests: line 243: return: can only `return' from a function or sourced script +./errors.tests: line 247: break: 0: loop count out of range +./errors.tests: line 251: continue: 0: loop count out of range +./errors.tests: line 256: builtin: bash: not a shell builtin +./errors.tests: line 260: bg: no job control +./errors.tests: line 261: fg: no job control +./errors.tests: line 264: kill: -s: option requires an argument +./errors.tests: line 266: kill: S: invalid signal specification +./errors.tests: line 268: kill: `': not a pid or valid job spec kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec] -./errors.tests: line 268: set: trackall: invalid option name -./errors.tests: line 272: xx: readonly variable +./errors.tests: line 273: set: trackall: invalid option name +./errors.tests: line 277: xx: readonly variable 1 ./errors1.sub: line 14: .: -i: invalid option .: usage: . filename [arguments] @@ -174,14 +176,14 @@ after non-special builtin: 0 ./errors7.sub: line 25: x: readonly variable after special builtin: 0 ./errors7.sub: line 27: x: readonly variable +./errors7.sub: line 29: x: readonly variable ./errors7.sub: line 21: x: readonly variable -./errors7.sub: line 21: notthere: command not found -after no such command: 127 +after no such command: 1 ./errors7.sub: line 23: x: readonly variable -echo builtin -after non-special builtin: 0 +after non-special builtin: 1 ./errors7.sub: line 25: x: readonly variable ./errors7.sub: line 27: x: readonly variable +./errors7.sub: line 29: x: readonly variable ./errors8.sub: eval: line 7: syntax error: unexpected end of file ok 1 ./errors8.sub: line 8: v: readonly variable @@ -194,7 +196,13 @@ ok 4 ok 5 ./errors8.sub: line 14: set: notanoption: invalid option name ok 6 +DEBUG +./errors9.sub: line 6: [[: ++: syntax error: operand expected (error token is "+") +DEBUG +./errors9.sub: line 8: ((: -- : syntax error: operand expected (error token is "- ") +DEBUG +./errors9.sub: line 10: ((: -- : syntax error: operand expected (error token is "- ") bash: line 1: return: can only `return' from a function or sourced script after return bash: line 1: return: can only `return' from a function or sourced script -./errors.tests: line 299: `!!': not a valid identifier +./errors.tests: line 305: `!!': not a valid identifier diff --git a/tests/errors.tests b/tests/errors.tests index 531b625b..0880bb55 100644 --- a/tests/errors.tests +++ b/tests/errors.tests @@ -57,6 +57,11 @@ unset -f func declare -fr func declare -f +r func +# cannot use declare -f in combination with other attributes +a() { echo a; } +declare -f -a a +declare -f -i b c + XPATH=$PATH declare -r XPATH unset -v XPATH @@ -176,9 +181,9 @@ declare -p unset # iteration variable in a for statement being readonly for VAR in 1 2 3 ; do echo $VAR; done -# parser errors -: $( for z in 1 2 3; do ) -: $( for z in 1 2 3; done ) +# parser errors; caught early so we have to run them in subshells +${THIS_SH} -c ': $( for z in 1 2 3; do )' comsub +${THIS_SH} -c ': $( for z in 1 2 3; done )' comsub # various `cd' errors ( unset HOME ; cd ) @@ -287,6 +292,7 @@ ${THIS_SH} ./errors7.sub ${THIS_SH} -o posix ./errors7.sub ${THIS_SH} ./errors8.sub +${THIS_SH} ./errors9.sub ${THIS_SH} -c 'return ; echo after return' bash ${THIS_SH} -o posix -c 'return ; echo after return' bash diff --git a/tests/errors7.sub b/tests/errors7.sub index add8782a..544e3e4c 100644 --- a/tests/errors7.sub +++ b/tests/errors7.sub @@ -26,3 +26,5 @@ echo after non-special builtin: $? echo after special builtin: $? ) ( x=8 $nocmd echo after assignment error: $? ) +( x=8 +echo after assignment statement error: $? ) diff --git a/tests/errors9.sub b/tests/errors9.sub new file mode 100644 index 00000000..3a267046 --- /dev/null +++ b/tests/errors9.sub @@ -0,0 +1,14 @@ +trap 'echo DEBUG' DEBUG + +# make sure that the right command name appears in the error messages and +# that the DEBUG trap doesn't overwrite it + +[[ ++ -gt 3 ]] + +(( -- )) + +for (( -- ; ++; -- )) +do + echo bogus +done + diff --git a/tests/exec.right b/tests/exec.right index 0a249dda..ef02fbb4 100644 --- a/tests/exec.right +++ b/tests/exec.right @@ -20,8 +20,17 @@ after exec1.sub: one two three 126 0 this is bashenv -./exec3.sub: line 3: /tmp/bash-notthere: No such file or directory -127 +trap -- 'echo EXIT' EXIT +trap -- '' SIGTERM +trap -- 'echo USR1' SIGUSR1 +USR1 +./exec3.sub: line 27: /tmp/bash-notthere: No such file or directory +./exec3.sub: after failed exec: 127 +trap -- 'echo EXIT' EXIT +trap -- '' SIGTERM +trap -- 'echo USR1' SIGUSR1 +USR1 +EXIT ./execscript: line 71: notthere: No such file or directory 127 ./execscript: line 74: notthere: No such file or directory @@ -133,3 +142,31 @@ w x y z +===== +WORKS +done +WORKS +a +b +c +d +a +b +c +d +e +A +B +c +d +c +d +e +x +y +z +WORKS +w +x +y +z diff --git a/tests/exec14.sub b/tests/exec14.sub index 3402fb95..eddd33fa 100644 --- a/tests/exec14.sub +++ b/tests/exec14.sub @@ -45,3 +45,20 @@ $THIS_SH -c '$binecho c && $binecho d && echo e' $THIS_SH -c 'trap "echo WORKS" EXIT ; $binecho x ; $binecho y ; $binecho z' ${THIS_SH} -c 'echo w ; { echo x ; $binecho y; }; $binecho z' + +echo ===== + +( trap "echo WORKS && rm $TMPDIR/x$$" EXIT && touch $TMPDIR/x$$ ) +( trap "echo WORKS && rm $TMPDIR/x$$" EXIT && touch $TMPDIR/x$$ ; $binecho done ) + +( echo a && { $binecho b && $binecho c ; } && echo d ) +( echo a && { $binecho b && $binecho c ; } && echo d ; $binecho e ) + +( echo A && $binecho B ) +( $binecho c && echo d ) + +( $binecho c && $binecho d && echo e ) + +( trap "echo WORKS" EXIT ; $binecho x ; $binecho y ; $binecho z ) + +( echo w ; { echo x ; $binecho y; }; $binecho z ) diff --git a/tests/exec3.sub b/tests/exec3.sub index 4f2f8e21..81b53b72 100644 --- a/tests/exec3.sub +++ b/tests/exec3.sub @@ -1,6 +1,37 @@ +# 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 <http://www.gnu.org/licenses/>. +# +# test the behavior of `execfail' not exiting an interactive shell +# added tests for changes in 10/2021 for preserving the traps across a failed +# exec + shopt -s execfail +trap 'echo EXIT' EXIT +trap 'echo USR1' USR1 +trap '' TERM +trap + +kill -s USR1 $$ # should run the trap + exec /tmp/bash-notthere + # make sure we're still around -echo $? +echo $0: after failed exec: $? + +trap +kill -s USR1 $$ # should run the trap +kill -s TERM $$ # should still be ignored +# this should run the exit trap +exit 0 diff --git a/tests/exp.right b/tests/exp.right index 4e88ca9b..60241a1d 100644 --- a/tests/exp.right +++ b/tests/exp.right @@ -227,15 +227,16 @@ argv[2] = <Y> argv[1] = <XY^AY> argv[1] = <x^Ay^?z> argv[1] = <x^Ay^?z> -declare -- var="xyz" +declare -- var=$'x\001y\177z' argv[1] = <declare> argv[2] = <--> -argv[3] = <var="x^Ay^?z"> +argv[3] = <var=$'x\001y\177z'> +var=x\001y\177z$ declare -- var="x\001y\177z"$ argv[1] = <$'x\001y\177z'> argv[1] = <x^Ay^?z> var=$'x\001y\177z' -./exp8.sub: line 29: xyz: syntax error: invalid arithmetic operator (error token is "z") +./exp8.sub: line 30: xyz: syntax error: invalid arithmetic operator (error token is "z") declare -a array=() declare -a array=([0]=$'x\001y\177z') argv[1] = <x^Ay^?z> @@ -408,3 +409,11 @@ cdefg abcdefg abcde abcdefg +foo +declare -- a="foo" +7 +declare -i a="7" +42 +declare -- a="42" +FOO +declare -u A="FOO" diff --git a/tests/exp.tests b/tests/exp.tests index 3e69db4f..61a39d3b 100644 --- a/tests/exp.tests +++ b/tests/exp.tests @@ -423,3 +423,4 @@ ${THIS_SH} ./exp9.sub ${THIS_SH} ./exp10.sub ${THIS_SH} ./exp11.sub ${THIS_SH} ./exp12.sub +${THIS_SH} ./exp13.sub diff --git a/tests/exp13.sub b/tests/exp13.sub new file mode 100644 index 00000000..80e14635 --- /dev/null +++ b/tests/exp13.sub @@ -0,0 +1,34 @@ +# 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 <http://www.gnu.org/licenses/>. +# +unset a + +echo ${a:=foo} +declare -p a + +unset a + +declare -i a +echo ${a:=4+3} +declare -p a + +unset a +echo ${a:=42} +declare -p a + +unset a +declare -u A +A= +echo ${A:=foo} + +declare -p A diff --git a/tests/exp8.sub b/tests/exp8.sub index 4c2870ca..7dd5a286 100644 --- a/tests/exp8.sub +++ b/tests/exp8.sub @@ -19,7 +19,8 @@ recho $var declare -p var recho $(declare -p var) -declare -p var | sed -n l +echo "var=$var" | sed -n l +echo "declare -- var=\"$var\"" | sed -n l recho ${var@Q} recho ${var@P} diff --git a/tests/exportfunc.right b/tests/exportfunc.right index ff7fc8d9..890bdfa4 100644 --- a/tests/exportfunc.right +++ b/tests/exportfunc.right @@ -4,7 +4,7 @@ exportfunc ok 2 ./exportfunc.tests: eval: line 44: syntax error: unexpected end of file ./exportfunc.tests: line 43: cve7169-bad2: No such file or directory ./exportfunc1.sub: line 14: maximum here-document count exceeded -./exportfunc.tests: line 64: HELLO_WORLD: No such file or directory +./exportfunc.tests: line 72: HELLO_WORLD: No such file or directory eval ok ./exportfunc3.sub: line 23: export: foo=bar: cannot export status: 1 diff --git a/tests/exportfunc.tests b/tests/exportfunc.tests index b2742d2c..d06b1a33 100644 --- a/tests/exportfunc.tests +++ b/tests/exportfunc.tests @@ -50,10 +50,18 @@ ${THIS_SH} ./exportfunc1.sub ${THIS_SH} ./exportfunc2.sub # CVE-2014-6277 +A100=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +A1000=${A100} + +for (( i = 0; i < 999; i++ )) +do + A1000+=${A100} +done env BASH_FUNC_foo%%="() { 000(){>0;}&000(){ 0;}<<0 0" ${THIS_SH} -c foo 2>/dev/null -env BASH_FUNC_foo%%="() { 000(){>0;}&000(){ 0;}<<`perl -e '{print "A"x100000}'` 0" ${THIS_SH} -c foo 2>/dev/null +env BASH_FUNC_foo%%="() { 000(){>0;}&000(){ 0;}<<${A1000} 0" ${THIS_SH} -c foo 2>/dev/null ${THIS_SH} -c "f(){ x(){ _;}; x(){ _;}<<a;}" 2>/dev/null +unset A100 A1000 # CVE-2014-6278 diff --git a/tests/extglob.right b/tests/extglob.right index 691f6879..2974ceca 100644 --- a/tests/extglob.right +++ b/tests/extglob.right @@ -92,16 +92,16 @@ a ab a ab a ab a -. .. -. .. a.log +*(.) +a.log *(foo) *(foo|bar) a.log ?(foo) a.log a.log -. .. -. .. +*(foo).* +*(foo|bar).* a.log a.log .x .y .z @@ -114,3 +114,71 @@ a b c .x .y .z a b c .x .y .z a b c * +.b a +.b a +a .b +.b +.b +.b a +.b a +a .b +.b +.b +dotglob: .a .foo bar +@(.foo) +.foo +!(.foo) +.a bar +@(.foo|*) +.a .foo bar +!(.foo|*) +!(.foo|*) +@(*) +.a .foo bar +!(*) +!(*) +.* +. .. .a .foo +@(.*) +. .. .a .foo +!(.*) +bar +no dotglob: .a .foo bar +@(.foo) +.foo +!(.foo) +bar +@(.foo|*) +.foo bar +!(.foo|*) +!(.foo|*) +!(bar).foo +!(bar).foo +*(bar).foo +.foo +?(bar).foo +.foo +.? +.. .a +@(.?) +.. .a +!(.?) +bar +dotglob: .a .foo bar +@(?|.?) +.. .a +@(?|.*) +. .. .a .foo +? .* +? . .. .a .foo +* +.a .foo bar +no dotglob: .a .foo bar +@(?|.?) +.. .a +@(?|.*) +. .. .a .foo +? .* +? . .. .a .foo +* +bar diff --git a/tests/extglob.tests b/tests/extglob.tests index 4cb671a8..7a7cf91b 100644 --- a/tests/extglob.tests +++ b/tests/extglob.tests @@ -380,13 +380,11 @@ shopt -u globstar builtin cd "$MYDIR" ${THIS_SH} ./extglob1.sub - ${THIS_SH} ./extglob1a.sub - ${THIS_SH} ./extglob3.sub - ${THIS_SH} ./extglob4.sub - ${THIS_SH} ./extglob5.sub +${THIS_SH} ./extglob6.sub +${THIS_SH} ./extglob7.sub exit 0 diff --git a/tests/extglob2.sub b/tests/extglob2.sub index f4a3b374..1088111f 100644 --- a/tests/extglob2.sub +++ b/tests/extglob2.sub @@ -2,6 +2,30 @@ LANG=en_US.UTF-8 shopt -s extglob a="aaaäöü" +a1=${a:3:3} + +[[ "${a}" == "${a1}" ]] || { + echo cond ok 1 +} + +case "${a//?aa}" in +"${a1}") echo ok 1;; +*) echo bad 1;; +esac + +case "${a//\aaa}" in +"${a1}") echo ok 2;; +*) echo bad 2;; +esac + +case "${a//aaa}" in +"${a1}") echo ok 3;; +*) echo bad 3;; +esac + +case "${a//@(?aa)}" in +"${a1}") echo ok 4;; +*) echo bad 4;; +esac -echo "${a}" "${a//?aa}" "${a//\aaa}" exit 0 diff --git a/tests/extglob6.sub b/tests/extglob6.sub new file mode 100644 index 00000000..5e2aafbe --- /dev/null +++ b/tests/extglob6.sub @@ -0,0 +1,43 @@ +# 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 <http://www.gnu.org/licenses/>. +# +# issues with ? matching "." in certain special circumstances with dotglob set + +shopt -s dotglob extglob + +DIR=$TMPDIR/extglob-$$ +mkdir $DIR +cd $DIR + +touch a .b + +LC_COLLATE=C # fix sort order + +echo @(?|.?) +echo @(.?|?) +echo ? .? + +echo .* +echo \.* + +shopt -u dotglob + +echo @(?|.?) +echo @(.?|?) +echo ? .? + +echo .* +echo \.* + +cd $OLDPWD +rm -rf $DIR diff --git a/tests/extglob7.sub b/tests/extglob7.sub new file mode 100644 index 00000000..5fab9cda --- /dev/null +++ b/tests/extglob7.sub @@ -0,0 +1,97 @@ +: ${TMPDIR:=/tmp} + +TESTDIR=$TMPDIR/glob-test-$$ +mkdir $TESTDIR || { + echo "$TESTDIR: cannot create" >&2 + exit 1 +} +cd $TESTDIR || { + echo "$TESTDIR: cannot cd" >&2 + exit 1 +} + +LC_CTYPE=C LC_COLLATE=C +shopt -s extglob dotglob +shopt -u globskipdots # XXX - backwards compatibility +touch .foo bar .a + +echo dotglob: .a .foo bar + +echo '@(.foo)' +echo @(.foo) +echo '!(.foo)' +echo !(.foo) + +echo '@(.foo|*)' +echo @(.foo|*) +echo '!(.foo|*)' +echo !(.foo|*) + +echo '@(*)' +echo @(*) +echo '!(*)' +echo !(*) + +echo '.*' +echo .* +echo '@(.*)' +echo @(.*) +echo '!(.*)' +echo !(.*) + +shopt -u dotglob + +echo no dotglob: .a .foo bar + +echo '@(.foo)' +echo @(.foo) +echo '!(.foo)' +echo !(.foo) + +echo '@(.foo|*)' +echo @(.foo|*) +echo '!(.foo|*)' +echo !(.foo|*) + +echo '!(bar).foo' +echo !(bar).foo +echo '*(bar).foo' +echo *(bar).foo +echo '?(bar).foo' +echo ?(bar).foo + +echo '.?' +echo .? +echo '@(.?)' +echo @(.?) +echo '!(.?)' +echo !(.?) + +shopt -s dotglob +echo dotglob: .a .foo bar + +echo '@(?|.?)' +echo @(?|.?) +echo '@(?|.*)' +echo @(?|.*) +echo '? .*' +echo ? .* +echo '*' +echo * + +shopt -u dotglob +echo no dotglob: .a .foo bar + +echo '@(?|.?)' +echo @(?|.?) +echo '@(?|.*)' +echo @(?|.*) +echo '? .*' +echo ? .* +echo '*' +echo * + +rm -f .a bar .foo + +cd $OLDPWD +rm -rf $TESTDIR diff --git a/tests/func.tests b/tests/func.tests index fffe3d2b..e35ec2b8 100644 --- a/tests/func.tests +++ b/tests/func.tests @@ -11,6 +11,12 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # +# since we look at functions below, remove all functions now +funcs=$(compgen -A function) +if [ -n "$funcs" ]; then + unset -f $funcs +fi + a() { x=$((x - 1)) diff --git a/tests/getopts10.sub b/tests/getopts10.sub index cc8acb0c..49b2bfe9 100644 --- a/tests/getopts10.sub +++ b/tests/getopts10.sub @@ -15,10 +15,10 @@ set -- -a bb readonly OPTARG getopts :x x -echo OPTARG = $OPTARG x = $x +echo OPTARG = $OPTARG x = "$x" getopts x x -echo ${OPTARG-unset} x = $x +echo ${OPTARG-unset} x = "$x" typeset -r RO=foo typeset -n OPTARG=RO diff --git a/tests/glob.right b/tests/glob.right index 94966905..723ee7b4 100644 --- a/tests/glob.right +++ b/tests/glob.right @@ -121,6 +121,10 @@ a\*b a\*b* é/* é/* +a aa b bb +.a .aa .b .bb a aa b bb +.a .aa .b .bb +. .. .a .aa .b .bb argv[1] = <a> argv[2] = <abc> argv[3] = <abd> @@ -135,7 +139,7 @@ argv[2] = <abc> argv[3] = <abd> argv[4] = <abe> tmp/l1 tmp/l2 tmp/*4 tmp/l3 -./glob.tests: line 65: no match: tmp/*4 +./glob.tests: line 66: no match: tmp/*4 argv[1] = <bdir/> argv[1] = <*> argv[1] = <a*> diff --git a/tests/glob.tests b/tests/glob.tests index b35d7336..02d53026 100644 --- a/tests/glob.tests +++ b/tests/glob.tests @@ -30,6 +30,7 @@ ${THIS_SH} ./glob6.sub ${THIS_SH} ./glob7.sub ${THIS_SH} ./glob8.sub ${THIS_SH} ./glob9.sub +${THIS_SH} ./glob10.sub MYDIR=$PWD # save where we are diff --git a/tests/glob10.sub b/tests/glob10.sub new file mode 100644 index 00000000..7c14c0d2 --- /dev/null +++ b/tests/glob10.sub @@ -0,0 +1,32 @@ +# 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 <http://www.gnu.org/licenses/>. +# + +# test basic behavior of globskipdots +TDIR=/tmp/dotglob-$$ + +{ mkdir $TDIR && cd $TDIR; } || exit 1 + +touch a b aa bb .a .b .aa .bb + +echo * +shopt -s dotglob +echo * + +shopt -s globskipdots +echo .* +shopt -u globskipdots +echo .* + +cd $OLDPWD +rm -rf $TDIR diff --git a/tests/glob2.sub b/tests/glob2.sub index cabc3502..09cb6d51 100644 --- a/tests/glob2.sub +++ b/tests/glob2.sub @@ -13,6 +13,14 @@ # . ./test-glue-functions +# this locale causes problems all over the place +if locale -a | grep -i '^zh_HK\.big5hkscs' >/dev/null ; then + : +else + echo "glob2.sub: warning: you do not have the zh_HK.big5hkscs locale installed;" >&2 + echo "glob2.sub: warning: that will cause some of these tests to fail." >&2 +fi + var='ab\' case $var in diff --git a/tests/glob5.sub b/tests/glob5.sub index 5735715d..a0dd623f 100644 --- a/tests/glob5.sub +++ b/tests/glob5.sub @@ -11,6 +11,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # +[ $UID -eq 0 ] && { echo "glob5.sub: the test suite should not be run as root" >&2 ; } + ORIGD=$PWD : ${TMPDIR:=/var/tmp} diff --git a/tests/glob6.sub b/tests/glob6.sub index f26ae4d6..88429838 100644 --- a/tests/glob6.sub +++ b/tests/glob6.sub @@ -12,6 +12,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # # tests of the backslash-in-glob-patterns discussion on the austin-group ML +[ $UID -eq 0 ] && { echo "glob6.sub: the test suite should not be run as root" >&2 ; } : ${TMPDIR:=/var/tmp} diff --git a/tests/heredoc.right b/tests/heredoc.right index f6e53bea..cc193f66 100644 --- a/tests/heredoc.right +++ b/tests/heredoc.right @@ -67,13 +67,13 @@ qux bar qux abc def geh -./heredoc3.sub: line 23: warning: here-document at line 21 delimited by end-of-file (wanted `EOF') +./heredoc3.sub: line 20: warning: here-document at line 18 delimited by end-of-file (wanted `EOF') = here is the text = -./heredoc3.sub: line 29: warning: here-document at line 27 delimited by end-of-file (wanted `EOF') +./heredoc3.sub: line 26: warning: here-document at line 24 delimited by end-of-file (wanted `EOF') this paren ) is not a problem -./heredoc3.sub: line 35: warning: here-document at line 33 delimited by end-of-file (wanted `EOF') +./heredoc3.sub: line 32: warning: here-document at line 30 delimited by end-of-file (wanted `EOF') these balanced parens ( ) are not a problem -./heredoc3.sub: line 41: warning: here-document at line 39 delimited by end-of-file (wanted `EOF') +./heredoc3.sub: line 38: warning: here-document at line 36 delimited by end-of-file (wanted `EOF') quoted balanced parens \( ) are not a problem either more text in a subshell some more text in a different subshell @@ -100,7 +100,34 @@ argv[2] = <threefour> argv[1] = <two> argv[2] = <threefi> argv[3] = <ve> +1: OK +2: OK +3: OK +4: OK +5: OK +6: OK +7: OK +1: OK +2: OK +3: OK +4: OK +5: OK +5: OK +1: ${x#$'no\t'} +2: O${x#$'no\t'O} +3: ${x#n$'o\t'} +4: ${x#'no '} +5: ${x#$pat} +6: ${y#$'not'} +7: ${y#'not'} +./heredoc7.sub: line 17: warning: command substitution: 1 unterminated here-document +foo bar +./heredoc7.sub: line 21: after: command not found +./heredoc7.sub: line 29: warning: here-document at line 29 delimited by end-of-file (wanted `EOF') +./heredoc7.sub: line 29: foobar: command not found +./heredoc7.sub: line 30: EOF: command not found +grep: *.c: No such file or directory comsub here-string -./heredoc.tests: line 149: warning: here-document at line 147 delimited by end-of-file (wanted `EOF') +./heredoc.tests: line 156: warning: here-document at line 154 delimited by end-of-file (wanted `EOF') hi there diff --git a/tests/heredoc.tests b/tests/heredoc.tests index 430302f5..d10a7c10 100644 --- a/tests/heredoc.tests +++ b/tests/heredoc.tests @@ -137,6 +137,13 @@ ${THIS_SH} ./heredoc4.sub # heredoc tests that use different size documents to test pipe implementation ${THIS_SH} ./heredoc5.sub +# test $'...' and $"..." quoted strings in here-documents +${THIS_SH} ./heredoc6.sub + +# interaction between here-documents and command substitutions +${THIS_SH} ./heredoc7.sub + + echo $( cat <<< "comsub here-string" ) diff --git a/tests/heredoc6.sub b/tests/heredoc6.sub new file mode 100644 index 00000000..1d5fff09 --- /dev/null +++ b/tests/heredoc6.sub @@ -0,0 +1,50 @@ +# 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 <http://www.gnu.org/licenses/>. +# + +# test $'...' and $"..." strings in here documents (problem through bash-5.1) + +pat=$'no\t' +x=$'no\tOK' +y=notOK + +cat <<EOF +1: ${x#$'no\t'} +2: O${x#$'no\t'O} +3: ${x#n$'o\t'} +4: ${x#'no '} +5: ${x#$pat} +6: ${y#$'not'} +7: ${y#'not'} +EOF + +cat <<EOF +1: ${x#$"no "} +2: ${x#n$"o "} +3: O${x#n$"o "O} +4: ${x#"no "} +5: ${y#$"not"} +5: ${y#"not"} +EOF + +# we don't perform dollar-quote expansion if the here-doc delimiter is quoted + +cat <<\EOF +1: ${x#$'no\t'} +2: O${x#$'no\t'O} +3: ${x#n$'o\t'} +4: ${x#'no '} +5: ${x#$pat} +6: ${y#$'not'} +7: ${y#'not'} +EOF diff --git a/tests/heredoc7.sub b/tests/heredoc7.sub new file mode 100644 index 00000000..4119df19 --- /dev/null +++ b/tests/heredoc7.sub @@ -0,0 +1,29 @@ +# 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 <http://www.gnu.org/licenses/>. +# + +# should characters outside a command substitution be interpreted as a delimiter +# for a here-document started inside it? +echo $(cat << EOF) +foo +bar +EOF +after + +# should characters inside a command substitution be interpreted as a delimiter +# for a here-document started outside of it? + +cat <<EOF && grep $( + foobar +EOF +echo notthereanywhere) *.c diff --git a/tests/herestr.tests b/tests/herestr.tests index 6f4c74c2..c97fa4f2 100644 --- a/tests/herestr.tests +++ b/tests/herestr.tests @@ -11,6 +11,12 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # +# since we look at functions below, remove all functions now +funcs=$(compgen -A function) +if [ -n "$funcs" ]; then + unset -f $funcs +fi + # basics read x <<<"alpha" echo "$x" diff --git a/tests/history.right b/tests/history.right index 379de48b..5273de6b 100644 --- a/tests/history.right +++ b/tests/history.right @@ -140,9 +140,9 @@ three one two three -5.1 +5.2 echo ${BASH_VERSION%\.*} -5.1 +5.2 echo ${BASH_VERSION%\.*} a b @@ -264,3 +264,36 @@ out of range 3 12 echo out of range 3 out of range 4 13 fc -l 1 99 +1 +2 +3 +4 +5 +6 + 3 echo 3 + 4 echo 4 + 5 echo 5 + 6 echo 6 + 3 echo 3 + 4 echo 4 + 5 echo 5 +6 +7 + 4 echo 4 + 5 echo 5 + 6 echo 6 + 7 echo 7 + 4 echo 4 + 5 echo 5 + 6 echo 6 +7 +8 + 5 echo 5 + 6 echo 6 +9 +10 + 5 echo 5 + 6 echo 6 + 7 echo 9 + 8 echo 10 + 5 echo 10 diff --git a/tests/history.tests b/tests/history.tests index 53321f05..5826d130 100644 --- a/tests/history.tests +++ b/tests/history.tests @@ -130,3 +130,4 @@ ${THIS_SH} ./history2.sub ${THIS_SH} ./history3.sub ${THIS_SH} ./history4.sub ${THIS_SH} ./history5.sub +${THIS_SH} ./history6.sub diff --git a/tests/history6.sub b/tests/history6.sub new file mode 100644 index 00000000..a21d8d38 --- /dev/null +++ b/tests/history6.sub @@ -0,0 +1,55 @@ +# 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 <http://www.gnu.org/licenses/>. +# +: ${TMPDIR:=/tmp} + +HISTFILE=${TMPDIR}/history-$$ +HISTSIZE=4 +HISTIGNORE="history*" + +set -o history + +history -c + +echo 1 +echo 2 +echo 3 +echo 4 +echo 5 +echo 6 + +history + +history -d -1 +history + +echo 6 +echo 7 + +history +history -d -1 +history + +echo 7 +echo 8 +history -d -2--1 +history + +echo 9 +echo 10 +history +history -d 5-7 +history + +unset HISTFILE +exit 0 diff --git a/tests/intl.tests b/tests/intl.tests index c3000fc7..c4ff02c3 100644 --- a/tests/intl.tests +++ b/tests/intl.tests @@ -62,7 +62,7 @@ ${THIS_SH} ./intl2.sub # test splitting on characters instead of bytes ${THIS_SH} ./intl3.sub -${THIS_SH} ./unicode1.sub 2>/dev/null +${THIS_SH} ./unicode1.sub # 2>/dev/null ${THIS_SH} ./unicode2.sub ${THIS_SH} ./unicode3.sub 2>&1 diff --git a/tests/intl2.sub b/tests/intl2.sub index 64961bcb..2f3236e6 100644 --- a/tests/intl2.sub +++ b/tests/intl2.sub @@ -1,5 +1,25 @@ +# 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 <http://www.gnu.org/licenses/>. +# +# this locale causes problems all over the place unset LC_ALL LC_NUMERIC -export LANG=de_DE.UTF-8 +if locale -a | grep -i '^de_DE\.UTF.*8' >/dev/null ; then + export LANG=de_DE.UTF-8 +else + echo "intl2.sub: warning: you do not have the de_DE.UTF-8 locale installed;" >&2 + echo "intl2.sub: that will cause some of these tests to fail." >&2 +fi + printf '%.4f\n' 1 LANG=C printf '%.4f\n' 1 diff --git a/tests/jobs.right b/tests/jobs.right index 5d03b76b..0510e044 100644 --- a/tests/jobs.right +++ b/tests/jobs.right @@ -31,6 +31,8 @@ i killed it ./jobs5.sub: line 40: wait: %8: no such job 2: ok 2 2: ok 3 +127 +./jobs5.sub: line 71: declare: wpid: not found child1 exit status 0 [1]+ Running sleep 20 & ./jobs7.sub: line 5: fg: no current jobs diff --git a/tests/jobs4.sub b/tests/jobs4.sub index 7ecd7123..9f1cd040 100644 --- a/tests/jobs4.sub +++ b/tests/jobs4.sub @@ -34,4 +34,6 @@ wait # the sleep is intended to give the kill time to execute before the job # exits (sleep 1 ; cat ) & +# suppress any message about terminated process +exec 2>/dev/null kill -1 %% && echo i killed it || echo could not kill it diff --git a/tests/jobs5.sub b/tests/jobs5.sub index e6ffb44e..e348f2e2 100644 --- a/tests/jobs5.sub +++ b/tests/jobs5.sub @@ -59,3 +59,13 @@ disown -a unset bgpid1 bgpid2 bgpid3 unset wpid + +# now that we have no jobs, make sure that wait -n -p var leaves var unset +jobs +wait -n -p wpid +echo $wpid $? + +# make sure wait -p var does something useful without the -n option +jobs +wait -p wpid +declare -p wpid diff --git a/tests/jobs7.sub b/tests/jobs7.sub index 3e76db37..582365ff 100644 --- a/tests/jobs7.sub +++ b/tests/jobs7.sub @@ -3,4 +3,6 @@ set -m sleep 20 & echo $(jobs) echo $(fg %% ; jobs) +# suppress any message about sleep 20 being terminated +exec 2>/dev/null kill %1 diff --git a/tests/lastpipe.right b/tests/lastpipe.right index cca5938d..84e1e2ea 100644 --- a/tests/lastpipe.right +++ b/tests/lastpipe.right @@ -18,3 +18,5 @@ A2 B1 B2 HI -- 42 -- 0 42 +x=x +x=x diff --git a/tests/lastpipe.tests b/tests/lastpipe.tests index 775e81dd..f9d669dd 100644 --- a/tests/lastpipe.tests +++ b/tests/lastpipe.tests @@ -71,3 +71,4 @@ ${THIS_SH} ./lastpipe1.sub echo lastpipe1.sub returns $? ${THIS_SH} ./lastpipe2.sub +${THIS_SH} ./lastpipe3.sub diff --git a/tests/lastpipe3.sub b/tests/lastpipe3.sub new file mode 100644 index 00000000..b9222b8a --- /dev/null +++ b/tests/lastpipe3.sub @@ -0,0 +1,11 @@ +# problem in bash-5.1 running lastpipe in subshell if fd 0 is closed + +shopt -s lastpipe +exec 0<&- + +echo x | read x +echo x=$x +unset x + +echo x | cat | read x +echo x=$x diff --git a/tests/mapfile.right b/tests/mapfile.right index 143d6ddc..4452232d 100644 --- a/tests/mapfile.right +++ b/tests/mapfile.right @@ -151,6 +151,7 @@ a [27] aaa [28] aaa [29] aaa +declare -a array=([0]="a" [1]="b" [2]="c" [3]=$'\n') 1 2 3 4 5 foo 0 1 diff --git a/tests/mapfile.tests b/tests/mapfile.tests index 01f1f2e5..c2ea7d24 100644 --- a/tests/mapfile.tests +++ b/tests/mapfile.tests @@ -52,6 +52,11 @@ for (( i = 0 ; i < ${#E[@]} ; i++ )); do echo "${E[${i}]}" done -${THIS_SH} ./mapfile1.sub +unset -v s array +s=$'a\xffb\xffc\xff' +mapfile -t -d $'\xff' array <<<"$s" +declare -p array +unset -v s array +${THIS_SH} ./mapfile1.sub ${THIS_SH} ./mapfile2.sub diff --git a/tests/misc/run-r2.sh b/tests/misc/run-r2.sh index 0321a1bd..0321a1bd 100755..100644 --- a/tests/misc/run-r2.sh +++ b/tests/misc/run-r2.sh diff --git a/tests/misc/sigint-1.sh b/tests/misc/sigint-1.sh index 7b74c307..7b74c307 100755..100644 --- a/tests/misc/sigint-1.sh +++ b/tests/misc/sigint-1.sh diff --git a/tests/misc/sigint-2.sh b/tests/misc/sigint-2.sh index 69eaf56a..69eaf56a 100755..100644 --- a/tests/misc/sigint-2.sh +++ b/tests/misc/sigint-2.sh diff --git a/tests/misc/sigint-3.sh b/tests/misc/sigint-3.sh index 2627fe6c..2627fe6c 100755..100644 --- a/tests/misc/sigint-3.sh +++ b/tests/misc/sigint-3.sh diff --git a/tests/misc/sigint-4.sh b/tests/misc/sigint-4.sh index 587dd265..587dd265 100755..100644 --- a/tests/misc/sigint-4.sh +++ b/tests/misc/sigint-4.sh diff --git a/tests/nameref.right b/tests/nameref.right index 296105c9..83e9ee5b 100644 --- a/tests/nameref.right +++ b/tests/nameref.right @@ -348,6 +348,10 @@ declare -a v=([1]="1") declare -a v=([0]="0" [1]="1") declare -n n="v[1]" declare -a v=([0]="0") +./nameref15.sub: line 120: warning: xref: removing nameref attribute +declare -a xref=([1]="one") +./nameref15.sub: line 126: warning: xref: removing nameref attribute +declare -a xref=([1]="one") declare -n r1="y" declare -n r2="x" ./nameref16.sub: line 25: typeset: x: not found @@ -424,6 +428,23 @@ declare -a var=([123]="") declare -n ref="var[123]" ./nameref18.sub: line 67: declare: var[123]: not found declare -a var=([123]="X") +argv[1] = <1> +argv[2] = <2> +argv[3] = <3> +argv[1] = <1> +argv[2] = <2> +argv[3] = <3> +argv[1] = <1> +argv[2] = <2> +argv[3] = <3> +argv[1] = <1> +argv[2] = <2> +argv[3] = <3> +argv[1] = <1> +argv[2] = <2> +argv[3] = <31> +argv[4] = <2> +argv[5] = <3> declare -n foo="bar" declare -- foo="bar" ./nameref19.sub: line 22: declare: bar: not found @@ -440,6 +461,8 @@ declare -n foo="bar" declare -- bar declare -- foo="bar" declare -- bar +8 +declare -n ivar="foo" declare -a v=([0]="Y") r: <Y> v: <Y> @@ -483,3 +506,55 @@ declare -n ref="var" declare -ai var=([1]="0") declare -n ref="var" declare -- var="1" +a string with spaces +many spaces +declare -n foo="bar[0]" +declare -a bar=([0]=" still more spaces") +declare -n foo="bar[0]" +declare -a bar=([0]="spaces still more spaces") +./nameref22.sub: line 50: declare: array: reference variable cannot be an array +./nameref22.sub: line 53: declare: array[128]: reference variable cannot be an array +declare -a array=([0]="one" [1]="two" [2]="three") +declare -- array="(one two three)" +declare -a array=([0]="one" [1]="two" [2]="three") +./nameref22.sub: line 69: declare: `(one two three)': invalid variable name for name reference +./nameref22.sub: line 70: declare: array: reference variable cannot be an array +declare -a array=([0]="zero") +./nameref22.sub: line 74: declare: array: reference variable cannot be an array +declare -a array=([0]="one" [1]="two" [2]="three") +./nameref22.sub: line 79: declare: array: reference variable cannot be an array +declare -a array +declare -ai array=([0]="one") +declare -a array=([0]="zero") +declare -a array=([0]="one" [1]="two" [2]="three") +declare -ai a=([0]="5") +declare -ai a=([0]="6") +declare -ai a=([0]="1") +./nameref23.sub: line 15: declare: b: not found +declare -ai a=([0]="1") +declare -- b="1" +declare -ai a=([0]="1") +declare -- b="11" +declare -ai a=([0]="1") +declare -- b="110" +./nameref23.sub: line 25: declare: `1': invalid variable name for name reference +declare -ai a=([0]="1") +./nameref23.sub: line 27: declare: b: not found +declare -ai a=([0]="4") +declare -in b="a[0]" +declare -ai a=([0]="6") +declare -in b="a[0]" +foo +foo bar +declare -a a=([0]="" [1]="foo bar") +declare -n b="a[1]" +foo +foo bar +declare -a a=([0]="" [1]="foo bar") +declare -n b="a[1]" +12 +16 +declare -ai a=([0]="0" [1]="16") +12 +16 +declare -ai a=([0]="0" [1]="16") diff --git a/tests/nameref15.sub b/tests/nameref15.sub index cce8fbd9..e9a09eeb 100644 --- a/tests/nameref15.sub +++ b/tests/nameref15.sub @@ -115,3 +115,13 @@ v=(0 1) declare -n n=v[1] unset n declare -p n v + +declare -n xref +declare -a xref[1]=one +declare -p xref + +unset xref +declare -n xref +xref=array +declare -a xref[1]=one +declare -p xref diff --git a/tests/nameref18.sub b/tests/nameref18.sub index a29fe379..7a32877f 100644 --- a/tests/nameref18.sub +++ b/tests/nameref18.sub @@ -65,3 +65,19 @@ declare -p ref ${!ref} var declare +t ref ref=X declare -p ref ${!ref} var + +unset -n ref +unset var + +arr=(1 2 3) + +indir='arr[@]' +declare -n ref='arr[@]' + +recho "${!indir}" +recho ${!indir} + +recho "$ref" +recho $ref + +recho "${!indir}$ref" diff --git a/tests/nameref19.sub b/tests/nameref19.sub index b00f68e5..d4b900e8 100644 --- a/tests/nameref19.sub +++ b/tests/nameref19.sub @@ -62,3 +62,12 @@ declare bar declare -p foo bar declare +n foo declare -p foo bar + +# but when we add the nameref attribute, we remove other attributes + +declare -i ivar +ivar=4+4 +echo $ivar + +declare -n ivar=foo +declare -p ivar diff --git a/tests/nameref22.sub b/tests/nameref22.sub new file mode 100644 index 00000000..4e44fbb3 --- /dev/null +++ b/tests/nameref22.sub @@ -0,0 +1,97 @@ +# 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 <http://www.gnu.org/licenses/>. +# + +declare -n foo=bar + +declare foo='a string with spaces' +echo $foo + +unset foo +declare foo+='many spaces' +echo $foo + +unset foo # unsets bar +unset -n foo + +declare -a bar +declare -n foo='bar[0]' +declare foo+=' still more spaces' + +declare -p foo bar +unset -n foo +unset bar + +declare -a bar +declare -n foo='bar[0]' +declare foo=spaces +declare foo+=' still more spaces' + +declare -p foo bar + +unset -n foo +unset bar + +ray=ray + +declare -a array +array[0]=zero + +declare -n array +unset array + +declare -n array[128] +unset array + +declare -a array='(one two three)' +declare -p array +unset array + +declare array='(one two three)' +declare -p array +unset array + +declare -a ar$ray='(one two three)' +declare -p ar$ray +unset array + +declare -a array=(zero) +declare -n array='(one two three)' +declare -n array=three +declare -p array +unset array + +declare -n array=(one two three) +declare -p array +unset array + +declare -a array +declare -n array=one +declare -p array +unset array + +array=one +declare -i array[64]; +declare -p array +unset array + +declare -a array=zero +declare -p array +unset array + +declare -a array +declare array='(one two three)' +declare -p array +unset array + + diff --git a/tests/nameref23.sub b/tests/nameref23.sub new file mode 100644 index 00000000..358c381e --- /dev/null +++ b/tests/nameref23.sub @@ -0,0 +1,82 @@ +declare -ai a +a[0]=4 +declare -n b='a[0]' + +b+=1 ; declare -p a + +declare b+=1 ; declare -p a + +unset a b +unset -n b + +###### +declare -ai a=(1) +declare -in b="a[0]" +declare -p a b + +b+=1 ; declare -p a b +b+=1 ; declare -p a b +b+=0 ; declare -p a b + +unset a b + +##### +declare -ai a=(1) +declare -n b="1" +declare -p a +declare -np b + +unset a ; unset -n b + +##### +declare -ai a=('4'); +declare -n b='a[0]'; +declare -ni b; # this should maybe not be allowed, but it is for now +declare -p a b + +b+=2; +declare -p a b + +unset a ; unset -n b + +##### +f() +{ + local -a a=('' 'foo'); + local -n b=a[1]; + echo $b; + b+=\ bar; + echo $b; + declare -p a b; +} +f + +declare -a a=('' 'foo'); +declare -n b=a[1]; +echo $b; +b+=\ bar; +echo $b; +declare -p a b + +unset a ; unset -n b + +unset -f f +f() +{ + local -ai a=(0 12); + local -n b=a[1]; + echo $b; + b+=4; + echo $b; + declare -p a; +} +f + +declare -ai a=(0 12); +declare -n b=a[1]; +echo $b; +b+=4; +echo $b; +declare -p a + +unset a ; unset -n b diff --git a/tests/new-exp.right b/tests/new-exp.right index 752bba5c..e3dc40e1 100644 --- a/tests/new-exp.right +++ b/tests/new-exp.right @@ -617,7 +617,7 @@ c Sub = 0 2 4 8 <> <> <'ab '\''cd'\'' ef'> -./new-exp10.sub: line 24: ${x@C}: bad substitution +bash: line 1: ${x@C}: bad substitution <'ab'> <'cd ef'> <''> <'gh'> <'ab' 'cd ef' '' 'gh'> <'ab'> <'cd> <ef'> <''> <'gh'> @@ -625,7 +625,7 @@ c Sub = 0 2 4 8 <'ab cd'> <'4'> <'ab cd'> <> -argv[1] = <host(2)[5.1]$ > +argv[1] = <host(2)[5.2]$ > < > <' \t\n'> @@ -648,6 +648,7 @@ i declare -i foo A declare -A foo +./new-exp10.sub: line 118: ${V@}: bad substitution abcxxxdef abcÃ¥def ḅć @@ -703,11 +704,21 @@ aaa bbb a bbb aaa bb 'string' +'string' +'value with spaces' 'value with spaces' 'a b' 'c d' 'e f' 'a b' 'c d' 'e f' 0 "zero" 1 "one" 2 "two" 3 "three" 0 "zero z" 1 "one o" 2 "two t" 3 "three t" +argv[1] = <0> +argv[2] = <zero z> +argv[3] = <1> +argv[4] = <one o> +argv[5] = <2> +argv[6] = <two t> +argv[7] = <3> +argv[8] = <three t> declare -a foo=() ai declare -ai foo @@ -719,6 +730,65 @@ a a a a +/homes/chetdefg +/homes/chetdefg +~defg +defg +defg +defg +$'&' $'&' $'&' $'&' $'&' $'&' $'&' +$'a' $'b' $'c' $'d' $'e' $'f' $'g' +a b c d e f g +a b c d e f g +& & & & & & & +& & & & & & & +& & & & & & & +\& \& \& \& \& \& \& +a a a a a a a +3 3 3 3 3 3 3 +abc defg +abc defg +& defg +& defg +& defg +\& defg +\abc defg +abcdefg +&defg +\abcdefg +\&defg +\&defg +\abcdefg +\\&defg +&defg +&defg +\&defg +\&defg +\\&defg +letx&yee +letx&yee +letxssyee +letxssyee +letx\&yee +letx\&yee +letx&yee +letx&yee +let\&ee +let\\ssee +let\ssee +let\ssee +let\&ee +let\&ee +let&ee +let&ee +twoone +&twoone +onetwo +one&two +two +&two +otwone +&twone argv[1] = </> argv[1] = </> diff --git a/tests/new-exp.tests b/tests/new-exp.tests index 079426cb..c542313f 100644 --- a/tests/new-exp.tests +++ b/tests/new-exp.tests @@ -631,6 +631,10 @@ ${THIS_SH} ./new-exp14.sub # ongoing work with a/A parameter transformations and `nounset' ${THIS_SH} ./new-exp15.sub +# pattern substitution with `&' (quoted and unquoted) in the replacement string +${THIS_SH} ./new-exp16.sub + + # problems with stray CTLNUL in bash-4.0-alpha unset a a=/a diff --git a/tests/new-exp10.sub b/tests/new-exp10.sub index bf9ebe7a..5b199d4f 100644 --- a/tests/new-exp10.sub +++ b/tests/new-exp10.sub @@ -21,7 +21,9 @@ printf "<%s>" "${x@A}" ; echo x="ab 'cd' ef" printf "<%s> " "${x@Q}" ; echo -printf "<%s>" "${x@C}" +# this needs to be run in a subshell because invalid transformation operators +# are now treated as substitution errors, fatal in non-interactive shells +${THIS_SH} -c 'x=abcdef ; printf "<%s>" "${x@C}"' bash # if unquoted, normal word splitting happens set -- ab 'cd ef' '' gh @@ -111,3 +113,6 @@ declare -A foo echo ${foo@a} declare -p foo + +V=42 +echo ${V@} # error diff --git a/tests/new-exp14.sub b/tests/new-exp14.sub index b8bda8de..92f51ea1 100644 --- a/tests/new-exp14.sub +++ b/tests/new-exp14.sub @@ -1,4 +1,18 @@ -# test the other uses of the 'K' tranform operator +# 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 <http://www.gnu.org/licenses/>. +# + +# test the other uses of the 'K' transform operator and its sibling 'k' # the associative array tests are performed separately, since that was the # original motivation for this feature foo=string @@ -7,7 +21,9 @@ bar='value with spaces' set -- 'a b' 'c d' 'e f' echo ${foo@K} +echo ${foo@k} echo ${bar@K} +echo ${bar@k} echo ${@@K} echo "${@@K}" @@ -17,3 +33,4 @@ echo ${foo[@]@K} foo=( 'zero z' 'one o' 'two t' 'three t' ) echo ${foo[@]@K} +recho "${foo[@]@k}" diff --git a/tests/new-exp16.sub b/tests/new-exp16.sub new file mode 100644 index 00000000..2ed751d3 --- /dev/null +++ b/tests/new-exp16.sub @@ -0,0 +1,120 @@ +# 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 <http://www.gnu.org/licenses/>. +# + +HOME=/homes/chet +string=abcdefg +set -- a b c + +shopt -u patsub_replacement + +# verify existing behavior +echo ${string/abc/~} +echo "${string/abc/~}" +echo ${string/abc/"~"} + +echo ${string/abc/$notthere} +echo "${string/abc/$notthere}" +echo "${string/abc/"$notthere"}" + +echo ${string//?/\$\'&\' } + +shopt -s patsub_replacement + +echo ${string//?/\$\'&\' } + +echo ${string//?/& } +echo "${string//?/& }" + +echo ${string//?/\& } +echo "${string//?/\& }" +echo ${string//?/"& "} +echo ${string//?/"\& "} + +echo "${string//?/"a "}" +echo "${string//?/"$# "}" + +echo ${string/abc/& } +echo "${string/abc/& }" +echo ${string/abc/"& "} + +echo ${string/abc/\& } +echo "${string/abc/\& }" +echo ${string/abc/"\& "} +echo ${string/abc/\\& } + +rep='\\&' + +echo "${string/abc/&}" +echo ${string/abc/\&} +echo "${string/abc/\\&}" +echo ${string/abc/"\\&"} +echo "${string/abc/"\\&"}" +echo ${string/abc/$rep} +echo ${string/abc/"$rep"} + +shopt -u patsub_replacement + +echo "${string/abc/&}" +echo ${string/abc/\&} +echo "${string/abc/\\&}" +echo "${string/abc/"\\&"}" +echo ${string/abc/"$rep"} + +shopt -s patsub_replacement + +repl='x&y' +r2='x\&y' +var='letssee' + +pat=ss + +echo ${var//$pat/"$repl"} +echo "${var//$pat/"$repl"}" +echo ${var//$pat/$repl} +echo "${var//$pat/$repl}" + +echo ${var//$pat/"$r2"} +echo "${var//$pat/"$r2"}" +echo ${var//$pat/$r2} +echo "${var//$pat/$r2}" + +r2='\\&' +r3='\&' + +echo ${var//$pat/\\\&} +echo ${var//$pat/\\$r2} +echo ${var//$pat/\\&} +echo ${var//$pat/$r2} + +echo ${var//$pat/"\&"} +echo ${var//$pat/"$r3"} +echo ${var//$pat/"&"} +echo ${var//$pat/$r3} + +# these cases provide the same functionality as sed when given a BRE like +# `^' or `$', or when passed a null input line +one=one +null= + +echo ${one/#/&two} +echo ${one/#/\&two} + +echo ${one/%/&two} +echo ${one/%/\&two} + +echo ${null/#/&two} +echo ${null/#/\&two} + +echo ${one/#?/&two} +echo ${one/#?/\&two} diff --git a/tests/nquote.right b/tests/nquote.right index e3ae5558..31c35c3b 100644 --- a/tests/nquote.right +++ b/tests/nquote.right @@ -35,6 +35,10 @@ argv[1] = <hello, $world> ;foo argv[1] = <^I> argv[1] = <'A^IB'> +argv[1] = <a^Ib^Ic> +argv[1] = <$'a\tb\tc'> + AD +E hello' world hello world! hello' world! @@ -62,3 +66,15 @@ argv[1] = <^?> 0000000 esc fs gs rs us del nl 0000007 \q +foo +./nquote4.sub: line 6: quux: command not found +argv[1] = <a^A)b> +argv[1] = <a^Ab> +argv[1] = <^A> +argv[1] = <\^A> +0000000 a $ ' \ 0 1 ' b \n a 001 b \n +0000015 +0000000 a $ ' \ 0 1 ' b \n a 001 b \n +0000015 +0000000 A \n A \n +0000004 diff --git a/tests/nquote.tests b/tests/nquote.tests index 20d6415d..e4d1a56f 100644 --- a/tests/nquote.tests +++ b/tests/nquote.tests @@ -128,6 +128,15 @@ unset mytab recho "${mytab:-$'\t'}" recho "$( args $'A\tB' )" +# tests for $'...' not being expanded when inside double quotes +recho $'a\tb\tc' +recho "$'a\tb\tc'" + +# tests for $'...' being expanded in command substitution, and when +echo "$(echo $'\t\t\101\104\n\105')" + ${THIS_SH} ./nquote1.sub ${THIS_SH} ./nquote2.sub ${THIS_SH} ./nquote3.sub +${THIS_SH} ./nquote4.sub +${THIS_SH} ./nquote5.sub diff --git a/tests/nquote4.sub b/tests/nquote4.sub new file mode 100644 index 00000000..0d4a4955 --- /dev/null +++ b/tests/nquote4.sub @@ -0,0 +1,6 @@ +# make sure aliases containing new-style single quotes are expanded correctly + +shopt -s expand_aliases +alias foo=$'echo foo\n\nquux\n' + +foo diff --git a/tests/nquote5.sub b/tests/nquote5.sub new file mode 100644 index 00000000..97cbadc4 --- /dev/null +++ b/tests/nquote5.sub @@ -0,0 +1,36 @@ +# 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 <http://www.gnu.org/licenses/>. +# +. test-glue-functions + +recho $( echo a$'\01)'b ) +recho $( echo ab ) +recho $( echo \ ) +recho $( echo \\ ) + +LC_CTYPE=C +od -c <<EOF | _intl_normalize_spaces +a$'\01'b +ab +EOF + +od -c <<EOF | _intl_normalize_spaces +${none-a$'\01'b} +${none-ab} +EOF + +V=Aa$'\01'b +od -c <<EOF | _intl_normalize_spaces +${V%a$'\01'b} +${V%ab} +EOF diff --git a/tests/posix2.right b/tests/posix2.right index 40aea039..5d3f734a 100644 --- a/tests/posix2.right +++ b/tests/posix2.right @@ -1,6 +1,4 @@ Testing for POSIX.2 conformance -./posix2.tests: eval: line 195: syntax error near unexpected token `esac' -./posix2.tests: eval: line 195: `case esac in (esac) ;; *) echo "case esac test 3" ;; esac' -./posix2.tests: eval: line 197: syntax error near unexpected token `)' -./posix2.tests: eval: line 197: `case esac in esac) ;; *) echo "case esac test 4";; esac' +./posix2.tests: eval: line 199: syntax error near unexpected token `)' +./posix2.tests: eval: line 199: `case esac in esac) ;; *) echo "case esac test 4";; esac' All tests passed diff --git a/tests/posix2.tests b/tests/posix2.tests index 9b6c0932..0f5fce15 100644 --- a/tests/posix2.tests +++ b/tests/posix2.tests @@ -190,11 +190,13 @@ case esac in (foo|esac) ;; *) testfail "case esac test 1" ;; esac newtest case esac in foo|esac) ;; *) testfail "case esac test 2" ;; esac -# these are supposed to be syntax errors +# POSIX.2 grammar rule 4 problem through bash-5.1 newtest -eval 'case esac in (esac) ;; *) echo "case esac test 3" ;; esac' +eval 'case esac in (esac) ;; *) testfail "case esac test 3" ;; esac' + +# these are supposed to be syntax errors newtest -eval 'case esac in esac) ;; *) echo "case esac test 4";; esac' +eval 'case esac in esac) ;; *) echo "case esac test 4";; esac' && testfail 'case esac test 4' if [ $exitval = 0 ]; then echo "All tests passed" diff --git a/tests/posixexp.right b/tests/posixexp.right index e6bdbf4b..7204b960 100644 --- a/tests/posixexp.right +++ b/tests/posixexp.right @@ -275,14 +275,34 @@ argv[2] = <b> [ abc def ghi jkl / abc def ghi jkl ] [ abc def ghi jkl ] [ abc def ghi jkl / abc def ghi jkl / abc def ghi jkl ] -5: notOK +1: OK +2: $'not' +3: OK +4: OK +5: tOK OK OK -5: $'not\ttoo\nbad' +$'not' +OK +tOK +6: $'not\ttoo\nbad' +OKa ' b +OKa ' b +7: OK +8: OKa ' b +9: OKa " b +10: OKa " b +tOK +tOK +tOK +tOK +./posixexp7.sub: line 69: ${'x1'%'t'}: bad substitution +./posixexp7.sub: line 70: ${'x1'%'t'}: bad substitution +./posixexp7.sub: line 73: ${'x1'%'t'}: bad substitution +./posixexp7.sub: line 74: ${'x1'%'t'}: bad substitution "A" A argv[1] = <"A"> argv[1] = <A> argv[1] = <A> ./posixexp.tests: line 97: unexpected EOF while looking for matching `}' -./posixexp.tests: line 98: syntax error: unexpected end of file diff --git a/tests/posixexp7.sub b/tests/posixexp7.sub index 2e230cf8..4e3fa007 100644 --- a/tests/posixexp7.sub +++ b/tests/posixexp7.sub @@ -1,13 +1,76 @@ +# 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 <http://www.gnu.org/licenses/>. +# # test the effect of quotes on the WORD in the posix pattern removal operators -# a here document does not behave the same as double quotes +# x=notOK +x1=not + cat <<EOF -5: ${x#$'not'} +1: ${x#$'not'} +2: $'not' +3: ${x#"not"} +4: ${x#'not'} +5: ${x#${x1%'t'}} EOF echo "${x#'not'}" echo "${x#$'not'}" +echo "$'not'" +echo "${x#"not"}" +echo "${x#${x1%'t'}}" + +cat <<EOF +6: $'not\ttoo\nbad' +EOF + +x=OK$'a\t\'\tb' +echo OK$'a\t\'\tb' +echo "$x" + +cat <<EOF +7: ${x%$'a\t\'\tb'} +8: ${x#$'a\t\'\tb'} +EOF + +x=OK'a " b' + +cat <<EOF +9: ${x#'a " b'} +10: ${x#$'a " b'} +EOF + +x=notOK +x1=not + +# extquote makes these work +echo "${x#${$'x1'%$'t'}}" +cat <<EOF +${x#${$'x1'%$'t'}} +EOF +echo "${x#${$'x1'%'t'}}" +cat <<EOF +${x#${$'x1'%'t'}} +EOF + +# syntax errors + +echo "${x#${'x1'%'t'}}" +cat <<EOF +${x#${'x1'%'t'}} +EOF +echo "${x#${'x1'%$'t'}}" cat <<EOF -5: $'not\ttoo\nbad' +${x#${'x1'%$'t'}} EOF diff --git a/tests/precedence.tests b/tests/precedence.tests index 111bd231..111bd231 100755..100644 --- a/tests/precedence.tests +++ b/tests/precedence.tests diff --git a/tests/printf1.sub b/tests/printf1.sub index e4fb54b8..2cbbc6a6 100644 --- a/tests/printf1.sub +++ b/tests/printf1.sub @@ -24,7 +24,7 @@ printf "%s" "$vv" printf -v vv "one\ctwo\n" printf "%s" "$vv" -# and unrecognized backslash escapes should have the backslash preserverd +# and unrecognized backslash escapes should have the backslash preserved printf -v vv "4\.2\n" printf "%s" "$vv" diff --git a/tests/printf2.sub b/tests/printf2.sub index 45c48d4c..94a2bb10 100644 --- a/tests/printf2.sub +++ b/tests/printf2.sub @@ -1,6 +1,12 @@ unset LC_ALL LC_CTYPE -export LANG=en_US.UTF-8 +export LANG=C +case $(printf %d\\n \'A) in +65) ;; +*) echo "printf2.sub: character conversion failed" >&2 ;; +esac + +export LANG=en_US.UTF-8 case $(printf %d\\n \'À) in 192) exit 0;; *) echo "printf2.sub: multibyte character conversion failed" >&2 ; exit 2 ;; diff --git a/tests/quotearray.right b/tests/quotearray.right new file mode 100644 index 00000000..e6893659 --- /dev/null +++ b/tests/quotearray.right @@ -0,0 +1,152 @@ +declare -A assoc=(["x],b[\$(echo uname >&2)"]="1" ) +declare -A assoc=(["\$key"]="1" ["x],b[\$(echo uname >&2)"]="1" ) +declare -A assoc=(["\$key"]="1" ["x],b[\$(echo uname >&2)"]="2" ) +./quotearray.tests: line 31: ((: 'assoc[x\],b\[\$(echo uname >&2)]++' : syntax error: operand expected (error token is "'assoc[x\],b\[\$(echo uname >&2)]++' ") +declare -A assoc=(["\$key"]="1" ["x],b[\$(echo uname >&2)"]="2" ) +./quotearray.tests: line 34: ((: 'assoc[x\],b\[\$(echo uname >&2)]'++ : syntax error: operand expected (error token is "'assoc[x\],b\[\$(echo uname >&2)]'++ ") +declare -A assoc=(["\$key"]="1" ["x],b[\$(echo uname >&2)"]="2" ) +declare -A assoc=(["\$key"]="1" ["x],b[\$(echo uname >&2)"]="3" ) +4 +klmnopqrst +klmnopqrst +klmno +klmnopqrst +declare -A A=(["\$(echo %)"]="5" [%]="10" ["]"]="10" ) +declare -A A=(["~"]="42" ) +42 +declare -A A=(["~"]="43" ) +42 +declare -A A=(["~"]="43" ["~0"]="43" ) +12 +declare -a a=([0]="12" [1]="42") +2 +2 +declare -Ai assoc=(["']"]="3" ["\$var"]="1" ) +105 +declare -A assoc=(["\` echo >&2 foo\`"]="42" ["\$( echo >&2 bar)"]="63" ) +./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 147: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)") +1 +./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 153: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)") +1 +declare -A assoc +0 +0 +1 +0 +0 +0 +declare -A assoc=(["\` echo >&2 foo\`"]="128" [0]="0" ["]"]="12" ["x],b[\$(echo uname >&2)"]="42" ["~"]="42" ["\$( echo 2>& date)"]="foo" ) +foo +0 +0 +./quotearray1.sub: line 68: 0\],b\[1: syntax error: invalid arithmetic operator (error token is "\],b\[1") +declare -a array +0 +0 +0 +0 +1 +1 +declare -A aa=(["\$( echo 2>& date)"]="foo" ) +foo +0 +1 +1 +./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 +declare -A A=([$'\t']="2" [" "]="2" ) +declare -A A=([$'\t']="2" ["*"]="2" [" "]="2" ["]"]="2" ["@"]="2" ) +./quotearray2.sub: line 54: read: `A[]]': not a valid identifier +declare -A A=([$'\t']="X" ["*"]="X" [" "]="X" ["@"]="X" ) +./quotearray2.sub: line 62: printf: `A[]]': not a valid identifier +declare -A A=([$'\t']="X" ["*"]="X" [" "]="X" ["@"]="X" ) +./quotearray2.sub: line 70: declare: `A[]]=X': not a valid identifier +declare -A A=(["*"]="X" ["@"]="X" ) +./quotearray2.sub: line 78: declare: `A[]]=X': not a valid identifier +declare -A A=(["*"]="X" ["@"]="X" ) +./quotearray2.sub: line 89: let: assoc[x],b[$(echo: bad array subscript (error token is "b[$(echo") +declare -A assoc +declare -A assoc=(["\$(echo foo)"]="1" ) +0 +declare -A assoc=(["\$var"]="value" ) +declare -A assoc=(["\$var"]="value" ) +declare -A assoc=(["\$var"]="value" ) +declare -A assoc=() +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") +declare -a array=() +./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" ) +./quotearray4.sub: line 41: declare: assoc: not found +declare -A assoc=(["*"]="star" ["!"]="bang" ["@"]="at" ) +declare -A assoc=(["*"]="star" ["!"]="bang" ) +declare -A assoc=(["!"]="bang" ) +declare -A assoc=(["*"]="star" ["!"]="bang" ) +declare -A assoc=(["!"]="bang" ) +star bang at +star bang at +0 +0 +0 +1 +1 +declare -A assoc=(["*"]="star" ["!"]="bang" ["@"]=" key" ) +=== +1 +1 +declare -a array=([0]="1" [1]="2" [2]="3") +1 2 3 +1 2 3 +0 +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 new file mode 100644 index 00000000..e1ed83b0 --- /dev/null +++ b/tests/quotearray.tests @@ -0,0 +1,164 @@ +# 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 <http://www.gnu.org/licenses/>. +# + +# a set of tests for associative arrays in arithmetic contexts + +declare -A assoc +key='x],b[$(echo uname >&2)' + +(( assoc[$key]++ )) +declare -p assoc + +(( assoc['$key']++ )) +declare -p assoc + +(( assoc["$key"]++ )) +declare -p assoc + +declare -A assoc + +(( 'assoc[$key]++' )) +declare -p assoc + +(( 'assoc[$key]'++ )) +declare -p assoc + +(( "assoc[$key]++" )) +declare -p assoc + +unset assoc + +typeset -A a +b="80's" + +((++a[$b])) + +((++a["$b"])) +[[ $((++a[$b])) ]] +[[ $((++a["$b"])) ]] + +echo ${a[$b]} +unset a + +declare -A A + +string=abcdefghijklmnopqrstuvwxyz + +echo ${string:10:10} +k1='%' +k2='$(echo %)' + +A[%]=10 +A[']']=10 +A[$k2]=5 + +k3=']' + +echo ${string:A[%]:A[$k1]} +echo ${string:A[%]:A[$k2]} +echo ${string:A[%]:A[$k3]} + +declare -p A + +unset A string key + +key='~' + +declare -A A +A[$key]=42 + +declare -p A + +echo $(( A[$key]++ )) +declare -p A + +key='~0' +A[$key]=42 +echo $(( A[$key]++ )) +declare -p A + +declare -a a +key='~-2' +a[0]=12 +a[$key]=42 +echo $(( a[7<(4+2)] )) + +declare -p a + +unset A a key + +declare -A A +declare -a a + +sString="devel packager's guide" +i=2 + +A["$sString"]=$i +a[$i]=$sString + +echo "${A[${a[i]}]}" +echo ${A["${a[i]}"]} + +unset A a + +#LANG=C +unset var assoc +var=\'\] +declare -Ai assoc +assoc[$var]=1 +assoc[$var]+=1 +((assoc['$var']++)) +((assoc[$var]++)) +typeset -p assoc + +unset assoc + +declare -A assoc +key1='` echo >&2 foo`' +key2='$( echo >&2 bar)' + +assoc[$key1]=42 +assoc[$key2]=63 + +echo $(( assoc[$key1] + assoc[$key2] )) +declare -p assoc +unset assoc + +declare -a a +key='x],b[$(echo uname >&2)' +a[$key]=42 + +expr='a[$key]' + +(( $expr )) +echo $? + +echo $(( $expr )) +echo $? + +echo $(( expr )) +echo $? + +(( expr )) +echo $? + +${THIS_SH} ./quotearray1.sub +${THIS_SH} ./quotearray2.sub +${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 new file mode 100644 index 00000000..19741b1f --- /dev/null +++ b/tests/quotearray1.sub @@ -0,0 +1,131 @@ +# 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 <http://www.gnu.org/licenses/>. +# + +# arithmetic operators for conditional commands and arithmetic commands + +declare -A assoc +declare -a index + +key='x],b[$(echo uname >&2)' +key1=']' +key2='` echo >&2 foo`' +key3='~' +key4='7<(4+2)' +key5='$( echo 2>& date)' +key6='$(echo foo)' + +[[ -n assoc[$key] ]] +declare -p assoc + +assoc[$key]=42 +assoc[$key1]=12 +assoc[$key2]=128 +assoc[$key3]=42 +assoc[0]=0 + +[[ assoc[$key] -eq assoc[$key] ]] +echo $? + +[[ assoc[$key] -gt assoc[$key1] ]] +echo $? + +[[ assoc[$key2] -lt assoc[$key] ]] +echo $? + +[[ assoc[$key] -eq assoc[$key3] ]] +echo $? + +[[ index[7<(4+2)] -le assoc[0] ]] +echo $? +[[ index[$key4] -le assoc[0] ]] +echo $? + +assoc[$key5]=foo +declare -p assoc + +echo "${assoc[$key5]}" + +[[ -v assoc[$key5] ]] +echo $? +[[ -v assoc[$key] ]] +echo $? + +unset assoc + +declare -a array +index='0],b[1'; +((array[$index]++)) + +declare -p array + +unset array + +declare -A assoc + +assoc[$key]=42 +assoc[$key4]=42 + +[[ -v assoc[$key] ]] +echo $? +[[ -v assoc["$key"] ]] +echo $? + +[[ -v assoc[$key4] ]] +echo $? +[[ -v assoc["$key4"] ]] +echo $? + +[[ -v assoc['$key'] ]] +echo $? +[[ -v assoc['$key4'] ]] +echo $? + +unset -v assoc + +declare -A aa +aa[$key5]=foo + +declare -p aa +echo "${aa[$key5]}" + +[[ -v aa[$key5] ]] +echo $? + +[[ -v aa[$key] ]] +echo $? + +aa[$key6]=42 +# this still performs expansion +test -v aa["$key6"] +echo $? +# should be an error +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 new file mode 100644 index 00000000..056f8ca2 --- /dev/null +++ b/tests/quotearray2.sub @@ -0,0 +1,107 @@ +# 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 <http://www.gnu.org/licenses/>. +# + +# assoc_expand_once for builtins + +typeset -A a +a[0]=0 a[1]=1 + +let "a[\" \"]=11" ; typeset -p a ; a[0]=0 + +unset a + +# tests for `problem' keys when using associative arrays and assoc_expand_once +# deal with problems for now; this is a placeholder for if and when I fix them + +typeset -A a + +k='[' +echo $(( a[$k]=7 )) + +k=']' +echo $(( a[$k]=7 )) + +unset a + +declare -A A + +for k in $'\t' ' '; do + (( A[$k]=2 )) +done +declare -p A + +for k in ']' '*' '@'; do + (( A[$k]=2 )) +done + +declare -p A + +unset A +declare -A A + +for k in $'\t' ' ' ']' '*' '@'; do + read "A[$k]" <<< X +done +declare -p A + +unset A +declare -A A + +for k in $'\t' ' ' ']' '*' '@'; do + printf -v "A[$k]" "%s" X +done +declare -p A + +unset A +declare -A A + +for k in ']' '*' '@'; do + declare A[$k]=X +done +declare -p A + +unset A +declare -A A + +for k in ']' '*' '@'; do + declare "A[$k]=X" +done +declare -p A + +unset A + +# this isn't right yet, but changes will show up here +shopt -s assoc_expand_once +declare -A assoc +key='x],b[$(echo uname >&2)' + +let assoc[$key]++ +declare -p assoc + +unset assoc + +typeset -A assoc +at=@ + +key='$(echo foo)' + +assoc[$key]=1 +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 new file mode 100644 index 00000000..65f950d5 --- /dev/null +++ b/tests/quotearray3.sub @@ -0,0 +1,117 @@ +# 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 <http://www.gnu.org/licenses/>. +# + +# assoc_expand_once and unset builtin, which is treated specially + +declare -A assoc + +var=x123 +assoc['$var']=value +declare -p assoc + +shopt -u assoc_expand_once +unset "assoc[$var]" +declare -p assoc + +unset 'assoc[$var]' +declare -p assoc + +assoc['$var']=value +shopt -s assoc_expand_once +unset 'assoc[$var]' +declare -p assoc + +unset assoc +shopt -u assoc_expand_once + +declare -A a +a['$(echo foo)']=1 + +unset 'a[$(echo foo)]' +declare -p a + +key='$(echo foo)' +a[$key]=1 + +unset 'a[$key]' +declare -p a + +a[$key]=1 +unset "a[$key]" +declare -p a + +a[$key]=1 +unset a[$key] +declare -p a + +unset a + +typeset -A assoc +key=@ + +assoc[@]=at +assoc[!]=bang + +# this should only unset the element with key `@' +unset -v assoc[$key] +typeset -p assoc + +# this should check for assoc[@] and return 1 +test -v assoc[$key] +echo $? + +# this should too +[[ -v assoc[$key] ]] +echo $? + +unset assoc array + +declare -A assoc +declare -a array + +assoc=([@]=at [!]=bang) +declare -p assoc + +unset assoc[@] +declare -p assoc + +array=(1 2 3) +declare -p array + +# right now, this still unsets the entire array +unset array[@] +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/quotearray4.sub b/tests/quotearray4.sub new file mode 100644 index 00000000..964aac75 --- /dev/null +++ b/tests/quotearray4.sub @@ -0,0 +1,116 @@ +# 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 <http://www.gnu.org/licenses/>. +# + +# tests for builtins handling associative array keys `*' and `@', with some +# indexed array tests as well (backwards compatible) + +# derived from test cases posted to bug-bash by myoga.murase@gmail.com + +declare -A assoc +declare -a array + +assoc[@]=at +assoc[*]=star +assoc[!]=bang + +key=@ + +iref='array[@]' +aref='assoc[@]' + +declare -p assoc + +unset assoc[@] +declare -p assoc + +unset assoc[*] +declare -p assoc + +unset assoc +declare -p assoc + +declare -A assoc +assoc[@]=at +assoc[*]=star +assoc[!]=bang + +declare -p assoc + +unset assoc["$key"] +declare -p assoc + +unset assoc["*"] +declare -p assoc + +assoc[@]=at assoc[*]=star + +unset assoc['@'] +declare -p assoc + +unset assoc['*'] + +declare -p assoc + +assoc[@]=at assoc[*]=star +echo ${!aref} + +declare -n nref=$aref +echo ${nref} +unset -n nref + +# for associative arrays, test -v treats @ and * as keys + +test -v 'assoc[@]' +echo $? +test -v assoc[$key] +echo $? +[[ -v assoc[$key] ]] +echo $? + +unset -v 'assoc[@]' + +test -v 'assoc[@]' +echo $? +[[ -v assoc[@] ]] +echo $? + +assoc[@]=at + +printf -v assoc[@] "%10s" key +declare -p assoc + +echo === +array=() +test -v array[@] +echo $? +[[ -v array[@] ]] +echo $? + +array=(1 2 3) +declare -p array + +echo ${!iref} +declare -n nref=$iref + +echo $nref +unset -n nref + +# but for indexed arrays, test -v treats @ and * as standing for the entire array +test -v 'array[@]' +echo $? +[[ -v array[@] ]] +echo $? + +printf -v array[@] "%-10s" key +declare -p array 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 <http://www.gnu.org/licenses/>. +# + +# 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 diff --git a/tests/read.right b/tests/read.right index 11440837..e21fcb5f 100644 --- a/tests/read.right +++ b/tests/read.right @@ -30,19 +30,24 @@ argv[1] = <foo> argv[1] = <foo> argv[1] = < foo> a = abcdefg +xyz a = xyz a = -xyz 123- a = abc timeout 1: ok - +unset or null 1 timeout 2: ok - -./read2.sub: line 36: read: -3: invalid timeout specification +unset or null 2 +timeout 3: ok +unset or null 3 +./read2.sub: line 45: read: -3: invalid timeout specification 1 abcde +abcde ./read3.sub: line 17: read: -1: invalid number abc +defg ab abc # @@ -64,3 +69,17 @@ FOO 0 0 1 +timeout 1: ok +unset or null 1 +timeout 2: ok +unset or null 2 +timeout 3: ok +unset or null 3 +timeout 4: ok +abcde +abcde + +one +two three four +one +two three four diff --git a/tests/read.tests b/tests/read.tests index 7384f05f..6132b6fe 100644 --- a/tests/read.tests +++ b/tests/read.tests @@ -109,3 +109,9 @@ ${THIS_SH} ./read5.sub # test behavior of read -t 0 ${THIS_SH} ./read6.sub + +# test behavior of readline timeouts +${THIS_SH} ./read7.sub + +# test behavior of read -n and read -d on regular files +${THIS_SH} ./read8.sub diff --git a/tests/read1.sub b/tests/read1.sub index b3b85157..cf003986 100644 --- a/tests/read1.sub +++ b/tests/read1.sub @@ -15,6 +15,7 @@ a=7 echo 'abcdefg|xyz' | { read -d '|' a echo a = "${a-unset}" + cat - # make sure we don't read too much } echo xyz 123 | { diff --git a/tests/read2.sub b/tests/read2.sub index 41698e46..d3530115 100644 --- a/tests/read2.sub +++ b/tests/read2.sub @@ -11,27 +11,36 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # +: ${TMPDIR:=/var/tmp} + a=4 -read -t 2 a < /dev/tty +read -t 1 a < /dev/tty estat=$? if [ $estat -gt 128 ]; then echo timeout 1: ok else echo $estat fi +echo ${a:-unset or null 1} -echo $a - -sleep 5 | read -t 1 a +read -t 0.000001 a < /dev/tty estat=$? if [ $estat -gt 128 ]; then echo timeout 2: ok else echo $estat fi +echo ${a:-unset or null 2} -echo $a +sleep 1 | read -t 0.25 a +estat=$? +if [ $estat -gt 128 ]; then + echo timeout 3: ok +else + echo $estat +fi +echo ${a:-unset or null 3} read -t -3 a < /dev/tty echo $? @@ -40,6 +49,24 @@ echo $a # the above should all time out echo abcde | { - read -t 2 a + read -t 0.5 a echo $a } + +read -t .0001 a <<<abcde +echo $a + +# this is the original test that prompted the change to sh_timers +cd $TMPDIR +rm -f a.pipe +mkfifo a.pipe +exec 9<> a.pipe +rm -f a.pipe + +for c in {0..2000}; do + (eval "echo {0..$c}" & read -u 9 -t 0.0001) >/dev/null + printf $'ok %d' "$c" >/dev/null +done + +cd $OLDPWD +rm -f $TMPDIR/a.pipe # paranoia diff --git a/tests/read3.sub b/tests/read3.sub index d413f7db..8a240401 100644 --- a/tests/read3.sub +++ b/tests/read3.sub @@ -20,6 +20,7 @@ read -n -1 echo abcdefg | { read -n 3 xyz echo $xyz + cat - # make sure we don't read too much } # fewer chars than specified diff --git a/tests/read7.sub b/tests/read7.sub new file mode 100644 index 00000000..553070f4 --- /dev/null +++ b/tests/read7.sub @@ -0,0 +1,66 @@ +# 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 <http://www.gnu.org/licenses/>. +# +# test behavior of native readline timeouts + +# turn off bracketed paste to avoid spurious output +bind 'set enable-bracketed-paste off' 2>/dev/null + +read -t 0.00001 -e var +estat=$? +if [ $estat -gt 128 ]; then + echo timeout 1: ok +else + echo $estat +fi +echo ${var:-unset or null 1} + +read -e -t 0.1 var +estat=$? +if [ $estat -gt 128 ]; then + echo timeout 2: ok +else + echo $estat +fi +echo ${var:-unset or null 2} + +read -e -t 1 var < /dev/tty +estat=$? +if [ $estat -gt 128 ]; then + echo timeout 3: ok +else + echo $estat +fi +echo ${var:-unset or null 3} + +sleep 1 | read -t 0.25 -e a +estat=$? +if [ $estat -gt 128 ]; then + echo timeout 4: ok +else + echo $estat +fi + +# the above should all time out +echo abcde | { + read -e -t 0.5 a + echo $a +} + +read -e -t .0001 a <<<abcde +echo $a + +set -o posix +read -t 0.1 a </dev/tty +echo $a + diff --git a/tests/read8.sub b/tests/read8.sub new file mode 100644 index 00000000..d5b7af8d --- /dev/null +++ b/tests/read8.sub @@ -0,0 +1,15 @@ +tmpf=$TMPDIR/tmp-$$ +printf "%s\n" "one two three four" > $tmpf + +# make sure we rewind the input properly when reading a specific number of +# characters or using a non-standard delimiter from a regular file + +exec <$tmpf +read -n 4 input && echo "$input" +cat - + +exec <$tmpf +read -d ' ' input && echo "$input" +cat - + +rm -f $tmpf diff --git a/tests/rsh.right b/tests/rsh.right index a91974a5..5f64049b 100644 --- a/tests/rsh.right +++ b/tests/rsh.right @@ -13,7 +13,7 @@ ./rsh.tests: line 37: /tmp/restricted: restricted: cannot redirect output ./rsh.tests: line 42: command: -p: restricted ./rsh.tests: line 44: set: +r: invalid option -set: usage: set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...] +set: usage: set [-abefhkmnptuvxBCEHPT] [-o option-name] [--] [-] [arg ...] ./rsh.tests: line 45: set: restricted: invalid option name ./rsh.tests: line 47: exec: restricted ./rsh.tests: after exec diff --git a/tests/run-all b/tests/run-all index b8219b2d..1f749239 100644 --- a/tests/run-all +++ b/tests/run-all @@ -23,12 +23,12 @@ SUFFIX=`${THIS_SH} -c 'echo $(( $RANDOM + $BASHPID ))'` BASH_TSTOUT=${TMPDIR}/bashtst-$SUFFIX # for now export BASH_TSTOUT -trap 'rm -f $BASH_TSTOUT' 0 1 2 3 15 +trap 'rm -f $BASH_TSTOUT ; exit' 1 2 3 15 +trap 'rm -f $BASH_TSTOUT' 0 PATH=.:$PATH # just to get recho/zecho/printenv if not run via `make tests' export PATH - # unset BASH_ENV only if it is set [ "${BASH_ENV+set}" = "set" ] && unset BASH_ENV # can't reliably do it for SHELLOPTS; SHELLOPTS is readonly in bash diff --git a/tests/run-execscript b/tests/run-execscript index de786442..c3ed53e6 100644 --- a/tests/run-execscript +++ b/tests/run-execscript @@ -1,5 +1,22 @@ +# 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 <http://www.gnu.org/licenses/>. +# + echo "warning: the text of a system error message may vary between systems and" >&2 echo "warning: produce diff output." >&2 +echo "warning: UNIX versions number signals differently." >&2 +echo "warning: If output differing only in line numbers is produced, please" >&2 +echo "warning: do not consider this a test failure." >&2 echo "warning: if the text of the error messages concerning \`notthere' or" >&2 echo "warning: \`/tmp/bash-notthere' not being found or \`/' being a directory" >&2 echo "warning: produce diff output, please do not consider this a test failure" >&2 diff --git a/tests/run-intl b/tests/run-intl index c31d1d0a..8234f280 100644 --- a/tests/run-intl +++ b/tests/run-intl @@ -1,8 +1,5 @@ # See whether or not we can use `diff -a' ( diff -a ./intl.right ./intl.right >/dev/null 2>&1 ) && AFLAG=-a -echo "warning: some of these tests will fail if you do not have UTF-8" >&2 -echo "warning: locales installed on your system." >&2 - ${THIS_SH} ./intl.tests > ${BASH_TSTOUT} diff $AFLAG ${BASH_TSTOUT} intl.right && rm -f ${BASH_TSTOUT} diff --git a/tests/run-minimal b/tests/run-minimal index ade30b15..0c3a2e5f 100644 --- a/tests/run-minimal +++ b/tests/run-minimal @@ -58,8 +58,8 @@ do run-ifs-tests|run-input-test|run-invert|run-more-exp|run-nquote) echo $x ; sh $x ;; run-ifs-posix|run-posix2|run-posixpat|run-posixpipe) echo $x ; sh $x ;; run-precedence|run-quote|run-read|run-rhs-exp|run-strip|run-tilde) echo $x ; sh $x ;; - run-dynvar) echo $x ; sh $x ;; - ;; + run-dynvar|run-iquote) echo $x ; sh $x ;; + run-type|run-comsub-eof|run-comsub-posix) echo $x ; sh $x ;; *) ;; esac rm -f "$BASH_TSTOUT" diff --git a/tests/run-quotearray b/tests/run-quotearray new file mode 100644 index 00000000..06e5e6eb --- /dev/null +++ b/tests/run-quotearray @@ -0,0 +1,2 @@ +${THIS_SH} ./quotearray.tests >${BASH_TSTOUT} 2>&1 +diff ${BASH_TSTOUT} quotearray.right && rm -f ${BASH_TSTOUT} diff --git a/tests/shopt.right b/tests/shopt.right index 8cf46db6..d617c1d7 100644 --- a/tests/shopt.right +++ b/tests/shopt.right @@ -28,6 +28,7 @@ shopt -s extquote shopt -u failglob shopt -s force_fignore shopt -s globasciiranges +shopt -s globskipdots shopt -u globstar shopt -u gnu_errfmt shopt -u histappend @@ -46,13 +47,16 @@ shopt -u mailwarn shopt -u no_empty_cmd_completion shopt -u nocaseglob shopt -u nocasematch +shopt -u noexpand_translation shopt -u nullglob +shopt -s patsub_replacement shopt -s progcomp shopt -u progcomp_alias shopt -s promptvars shopt -u restricted_shell shopt -u shift_verbose shopt -s sourcepath +shopt -u varredir_close shopt -u xpg_echo -- shopt -u huponexit @@ -66,8 +70,10 @@ shopt -s expand_aliases shopt -s extquote shopt -s force_fignore shopt -s globasciiranges +shopt -s globskipdots shopt -s hostcomplete shopt -s interactive_comments +shopt -s patsub_replacement shopt -s progcomp shopt -s promptvars shopt -s sourcepath @@ -108,10 +114,12 @@ shopt -u mailwarn shopt -u no_empty_cmd_completion shopt -u nocaseglob shopt -u nocasematch +shopt -u noexpand_translation shopt -u nullglob shopt -u progcomp_alias shopt -u restricted_shell shopt -u shift_verbose +shopt -u varredir_close shopt -u xpg_echo -- autocd off @@ -150,10 +158,12 @@ mailwarn off no_empty_cmd_completion off nocaseglob off nocasematch off +noexpand_translation off nullglob off progcomp_alias off restricted_shell off shift_verbose off +varredir_close off xpg_echo off -- set +o allexport @@ -294,5 +304,9 @@ xtrace off -- ./shopt.tests: line 106: shopt: xyz1: invalid shell option name ./shopt.tests: line 107: shopt: xyz1: invalid option name +28c28 +< globskipdots off +--- +> globskipdots on expand_aliases on expand_aliases on diff --git a/tests/test.right b/tests/test.right index 391edbbd..4be22f4b 100644 --- a/tests/test.right +++ b/tests/test.right @@ -220,6 +220,8 @@ t ! -z "$z" 0 t ! -n "$z" 1 +t ! ! "$z" +0 t "$zero" 1 t ! "$zero" @@ -272,7 +274,7 @@ b ( 1 = 2 2 ./test.tests: line 26: test: too many arguments 2 -./test.tests: line 431: [: missing `]' +./test.tests: line 434: [: missing `]' 2 ./test.tests: line 26: test: (: unary operator expected 2 diff --git a/tests/test.tests b/tests/test.tests index 03e2754a..df4b8509 100644 --- a/tests/test.tests +++ b/tests/test.tests @@ -358,6 +358,9 @@ t ! -z "$z" echo 't ! -n "$z"' t ! -n "$z" +echo 't ! ! "$z"' +t ! ! "$z" + zero= echo 't "$zero"' t "$zero" diff --git a/tests/tilde.tests b/tests/tilde.tests index 374f3e6d..20268a73 100644 --- a/tests/tilde.tests +++ b/tests/tilde.tests @@ -86,7 +86,9 @@ echo ~$USER cd "$wdir" +# this test is incomplete; should also test assignment statements (tilde3.sub) +echo foo=bar:~ +set -o posix echo foo=bar:~ -set -o posix; echo foo=bar:~ exit 0 diff --git a/tests/tilde2.right b/tests/tilde2.right index fce04687..f383e3a3 100644 --- a/tests/tilde2.right +++ b/tests/tilde2.right @@ -22,3 +22,7 @@ HOME=~ /usr/$x/abc HOME=/usr/$x/abc /usr/$x/abc +foo=/home/xyz:/home/xyz +/home/xyz:/home/xyz +foo=~:~ +/home/xyz:/home/xyz diff --git a/tests/tilde2.tests b/tests/tilde2.tests index cc5dba9f..d2415cb3 100644 --- a/tests/tilde2.tests +++ b/tests/tilde2.tests @@ -81,3 +81,5 @@ set +o posix eval echo $h eval $h echo $HOME + +$THIS_SH ./tilde3.sub diff --git a/tests/tilde3.sub b/tests/tilde3.sub new file mode 100644 index 00000000..c35ea500 --- /dev/null +++ b/tests/tilde3.sub @@ -0,0 +1,26 @@ +# 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 <http://www.gnu.org/licenses/>. +# +# regression test for tilde expansion following unquoted colons in posix mode + +HOME=/home/xyz + +echo foo=~:~ +foo=~:~ +printf "%s\n" $foo + +set -o posix + +echo foo=~:~ +foo=~:~ +printf "%s\n" $foo diff --git a/tests/type.right b/tests/type.right index f876715a..bbc228e8 100644 --- a/tests/type.right +++ b/tests/type.right @@ -54,12 +54,12 @@ f () foo is a function foo () { - echo $(<x1) + echo $(< x1) } bar is a function bar () { - echo $(<x1) + echo $(< x1) } foo is a function foo () diff --git a/tests/unicode1.sub b/tests/unicode1.sub index fc742855..713ab40f 100644 --- a/tests/unicode1.sub +++ b/tests/unicode1.sub @@ -109,7 +109,13 @@ fr_FR_ISO_8859_1=( [0x00fb]=$'\373' [0x00fc]=$'\374' [0x00fd]=$'\375' [0x00fe]=$'\376' ) -TestCodePage fr_FR.ISO8859-1 fr_FR_ISO_8859_1 +# this locale causes problems all over the place +if locale -a | grep -i '^fr_FR\.ISO8859.*1$' >/dev/null ; then + TestCodePage fr_FR.ISO8859-1 fr_FR_ISO_8859_1 +else + echo "unicode1.sub: warning: you do not have the fr_FR.ISO8859-1 locale installed;" >&2 + echo "unicode1.sub: that will cause some of these tests to be skipped." >&2 +fi zh_TW_BIG5=( [0x00f6]=$'\366' [0x00f7]=$'\367' [0x00f8]=$'\370' [0x00f9]=$'\371' [0x00fa]=$'\372' @@ -309,8 +315,14 @@ jp_JP_SHIFT_JIS=( [0xFF9E]=$'\xDE' # HALFWIDTH KATAKANA VOICED SOUND MARK [0xFF9F]=$'\xDF' # HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK ) + #TestCodePage ja_JP.SHIFT_JIS jp_JP_SHIFT_JIS -TestCodePage ja_JP.SJIS jp_JP_SHIFT_JIS +if locale -a | grep -i '^ja_JP.SJIS' >/dev/null ; then + TestCodePage ja_JP.SJIS jp_JP_SHIFT_JIS +else + echo "unicode1.sub: warning: you do not have the ja_JP.SJIS locale installed;" >&2 + echo "unicode1.sub: that will cause some of these tests to be skipped." >&2 +fi #for ((x=1;x<1000;x++)); do printf ' [0x%04x]=%-11q' "$x" "$(printf "$(printf '\\U%08x' $x)")" ; [ $(($x%5)) = 0 ] && echo; done C_UTF_8=( diff --git a/tests/varenv.right b/tests/varenv.right index 358f5dc7..f6bd1b5b 100644 --- a/tests/varenv.right +++ b/tests/varenv.right @@ -168,10 +168,9 @@ after bar: var=global ./varenv13.sub: line 16: `var[0]': not a valid identifier ./varenv13.sub: line 16: `var[@]': not a valid identifier ./varenv13.sub: line 14: declare: var: not found -./varenv13.sub: line 25: var[@]: bad array subscript -declare -A var=([0]="X" ) +declare -A var=([0]="X" ["@"]="Y" ) help -./varenv13.sub: line 34: `var[0]': not a valid identifier +./varenv13.sub: line 35: `var[0]': not a valid identifier 1 declare -A var=([0]="X" ) declare -A var=([Y]="Y" ) @@ -265,6 +264,14 @@ ignoreeof off ignoreeof on 10 match 1 +trap -- 'echo trap:$FUNCNAME' EXIT +trap:f +trap -- 'echo trap:$FUNCNAME' EXIT +trap:f +trap -- 'echo trap:$FUNCNAME' EXIT +trap:f +trap -- 'echo trap:$FUNCNAME' EXIT +trap:f a=z a=b a=z diff --git a/tests/varenv.tests b/tests/varenv.tests index b058ed4f..68c619ec 100644 --- a/tests/varenv.tests +++ b/tests/varenv.tests @@ -259,6 +259,7 @@ ${THIS_SH} ./varenv18.sub ${THIS_SH} ./varenv19.sub ${THIS_SH} ./varenv20.sub ${THIS_SH} ./varenv21.sub +${THIS_SH} ./varenv22.sub # make sure variable scoping is done right tt() { typeset a=b;echo a=$a; };a=z;echo a=$a;tt;echo a=$a diff --git a/tests/varenv13.sub b/tests/varenv13.sub index 1f837ec7..1fa7d5b3 100644 --- a/tests/varenv13.sub +++ b/tests/varenv13.sub @@ -22,6 +22,7 @@ typeset -A var f() { declare -p ${!var*}; } +# this is no longer an error var[0]=X var[@]=Y f diff --git a/tests/varenv22.sub b/tests/varenv22.sub new file mode 100644 index 00000000..6d42bb57 --- /dev/null +++ b/tests/varenv22.sub @@ -0,0 +1,17 @@ +# test behavior of FUNCNAME in and out of parse_and_execute scenarios + +# in parse_and_execute +${THIS_SH} -c 'trap "echo trap:\$FUNCNAME" EXIT ; trap ; f() { exit; } ; f' bash + +${THIS_SH} << \EOF +eval "trap 'echo trap:\$FUNCNAME' EXIT ; trap; f() { exit; } ; f" +EOF + +# not in parse_and_execute +${THIS_SH} << \EOF +trap 'echo trap:$FUNCNAME' EXIT ; trap; f() { exit; } ; f +EOF + +# this has to be last +trap 'echo trap:$FUNCNAME' EXIT ; trap; f() { exit; } ; f + diff --git a/tests/vredir.right b/tests/vredir.right index b2c4cc9c..6465595b 100644 --- a/tests/vredir.right +++ b/tests/vredir.right @@ -98,3 +98,4 @@ swizzle () exec {stdin}<&${fd[0]}-; exec {stdout}>&${fd[1]}- } +./vredir8.sub: line 12: $fd: Bad file descriptor diff --git a/tests/vredir.tests b/tests/vredir.tests index ea59eecd..bd4cb775 100644 --- a/tests/vredir.tests +++ b/tests/vredir.tests @@ -57,5 +57,6 @@ ${THIS_SH} ./vredir5.sub ${THIS_SH} ./vredir6.sub ${THIS_SH} ./vredir7.sub +${THIS_SH} ./vredir8.sub exit 0 diff --git a/tests/vredir8.sub b/tests/vredir8.sub new file mode 100644 index 00000000..e87b45b3 --- /dev/null +++ b/tests/vredir8.sub @@ -0,0 +1,13 @@ +# test varredir_close + +: {fd}<>/dev/null + +echo redir 1 >&$fd +exec {fd}>&- + +shopt -s varredir_close + +: {fd}<>/dev/tty + +echo redir 2 >&$fd +exec {fd}>&- |