From 00edd0ee5051cd396c5594290bb21c212a9093e8 Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Thu, 28 Sep 2023 10:47:17 -0400 Subject: [PATCH] small changes to some error messages; greatly expanded builtins tests --- CWRU/CWRU.chlog | 16 +++ MANIFEST | 6 ++ builtins/break.def | 6 ++ builtins/shift.def | 11 +- subst.c | 35 +++--- tests/RUN-ONE-TEST | 2 +- tests/alias.right | 2 + tests/alias.tests | 4 + tests/arith-for.right | 6 ++ tests/arith-for.tests | 9 ++ tests/array.right | 12 ++- tests/array.tests | 3 + tests/builtins.right | 143 +++++++++++++++++++++++- tests/builtins.tests | 34 +++++- tests/builtins10.sub | 32 ++++++ tests/builtins8.sub | 16 +++ tests/builtins9.sub | 7 ++ tests/complete.right | 227 +++++++++++++++++++++++++++++++++++++++ tests/complete.tests | 14 +++ tests/comsub.right | 1 + tests/comsub.tests | 9 ++ tests/dynvar.right | 8 ++ tests/dynvar.tests | 26 ++++- tests/errors.right | 187 ++++++++++++++++++-------------- tests/errors.tests | 43 ++++++++ tests/errors1.sub | 9 +- tests/errors7.sub | 3 + tests/exec.right | 18 ++-- tests/execscript | 8 ++ tests/exp.right | 2 + tests/exp.tests | 9 ++ tests/func.right | 2 + tests/func5.sub | 16 +++ tests/getopts.right | 2 + tests/getopts10.sub | 6 ++ tests/glob-bracket.tests | 1 + tests/glob10.sub | 2 +- tests/glob8.sub | 2 +- tests/history.right | 13 +++ tests/history.tests | 1 + tests/history1.sub | 5 + tests/history8.sub | 16 +++ tests/invocation.right | 14 ++- tests/invocation.tests | 11 +- tests/invocation1.sub | 40 +++++++ tests/invocation2.sub | 50 +++++++++ tests/jobs.right | 33 +++--- tests/jobs.tests | 5 + tests/jobs5.sub | 5 + tests/jobs8.sub | 29 +++++ tests/new-exp.right | 27 ++--- tests/new-exp.tests | 5 + tests/printf.right | 33 +++--- tests/printf.tests | 17 +++ tests/printf1.sub | 4 + tests/read.right | 2 + tests/read.tests | 4 + tests/redir.right | 2 + tests/redir8.sub | 5 + tests/set-x.right | 3 + tests/set-x.tests | 2 + tests/test.right | 28 ++++- tests/test.tests | 41 +++++++ tests/trap.right | 14 +++ tests/trap.tests | 9 ++ tests/trap2.sub | 2 + tests/trap9.sub | 84 +++++++++++++++ tests/type.right | 12 ++- tests/type.tests | 9 +- tests/type5.sub | 41 +++++++ tests/varenv7.sub | 4 +- 71 files changed, 1330 insertions(+), 179 deletions(-) create mode 100644 tests/builtins10.sub create mode 100644 tests/history8.sub create mode 100644 tests/invocation1.sub create mode 100644 tests/invocation2.sub create mode 100644 tests/jobs8.sub create mode 100644 tests/trap9.sub create mode 100644 tests/type5.sub diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index e34b4179..7c204a1a 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -7677,3 +7677,19 @@ execute_cmd.c name is a fatal error, just like with `for'. This is compatible with ksh93 and mksh + 9/25 + ---- +subst.c + - parameter_brace_expand_length: rearrange the code slightly to reduce + the number of find_variable calls. This matters if the variable is + dynamic and produces a new value each time (e.g., RANDOM). + + 9/26 + ---- +builtins/shift.def + - shift_builtin: if get_numeric_arg returns a number out of range and + we're going to print an error message, make sure to skip over an + argument of `--' so we can print the right argument + +builtins/break.def + - break_builtin,continue_builtin: ditto with get_numeric_arg and `--' diff --git a/MANIFEST b/MANIFEST index 85b00403..16eac82f 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1025,6 +1025,7 @@ tests/builtins6.sub f tests/builtins7.sub f tests/builtins8.sub f tests/builtins9.sub f +tests/builtins10.sub f tests/source1.sub f tests/source2.sub f tests/source3.sub f @@ -1262,6 +1263,7 @@ tests/history4.sub f tests/history5.sub f tests/history6.sub f tests/history7.sub f +tests/history8.sub f tests/ifs.tests f tests/ifs.right f tests/ifs1.sub f @@ -1278,6 +1280,7 @@ tests/intl4.sub f tests/intl.right f tests/invocation.tests f tests/invocation.right f +tests/invocation1.sub f tests/iquote.tests f tests/iquote.right f tests/iquote1.sub f @@ -1291,6 +1294,7 @@ tests/jobs4.sub f tests/jobs5.sub f tests/jobs6.sub f tests/jobs7.sub f +tests/jobs8.sub f tests/jobs.right f tests/lastpipe.right f tests/lastpipe.tests f @@ -1568,12 +1572,14 @@ tests/trap5.sub f tests/trap6.sub f tests/trap7.sub f tests/trap8.sub f +tests/trap9.sub f tests/type.tests f tests/type.right f tests/type1.sub f tests/type2.sub f tests/type3.sub f tests/type4.sub f +tests/type5.sub f tests/unicode1.sub f tests/unicode2.sub f tests/unicode3.sub f diff --git a/builtins/break.def b/builtins/break.def index 820377e1..3a2fb851 100644 --- a/builtins/break.def +++ b/builtins/break.def @@ -73,6 +73,9 @@ break_builtin (WORD_LIST *list) if (newbreak <= 0) { + /* skip over `--' option to get the right error message */ + if (list && list->word && ISOPTION (list->word->word, '-')) + list = list->next; sh_erange (list->word->word, _("loop count")); breaking = loop_level; return (EXECUTION_FAILURE); @@ -114,6 +117,9 @@ continue_builtin (WORD_LIST *list) if (newcont <= 0) { + /* skip over `--' option to get the right error message */ + if (list && list->word && ISOPTION (list->word->word, '-')) + list = list->next; sh_erange (list->word->word, _("loop count")); breaking = loop_level; return (EXECUTION_FAILURE); diff --git a/builtins/shift.def b/builtins/shift.def index d6519c16..b8a4d8ff 100644 --- a/builtins/shift.def +++ b/builtins/shift.def @@ -68,6 +68,9 @@ shift_builtin (WORD_LIST *list) return (EXECUTION_SUCCESS); else if (times < 0) { + /* skip over `--' option to get the right error message */ + if (list && list->word && ISOPTION (list->word->word, '-')) + list = list->next; sh_erange (list ? list->word->word : NULL, _("shift count")); return (EXECUTION_FAILURE); } @@ -75,7 +78,13 @@ shift_builtin (WORD_LIST *list) if (times > nargs) { if (print_shift_error) - sh_erange (list ? list->word->word : NULL, _("shift count")); + { + /* skip over `--' option to get the right error message */ + if (list && list->word && ISOPTION (list->word->word, '-')) + list = list->next; + + sh_erange (list ? list->word->word : NULL, _("shift count")); + } return (EXECUTION_FAILURE); } else if (times == nargs) diff --git a/subst.c b/subst.c index 855ff745..9f4c4e54 100644 --- a/subst.c +++ b/subst.c @@ -8139,6 +8139,7 @@ parameter_brace_expand_length (char *name) SHELL_VAR *var; var = (SHELL_VAR *)NULL; + number = 0; if (name[1] == '\0') /* ${#} */ number = number_of_args (); @@ -8175,20 +8176,19 @@ parameter_brace_expand_length (char *name) else if (valid_array_reference (name + 1, 0)) number = array_length_reference (name + 1); #endif /* ARRAY_VARS */ + else if (legal_number (name + 1, &arg_index)) /* ${#1} */ + { + t = get_dollar_var_value (arg_index); + if (t == 0 && unbound_vars_is_error) + return INTMAX_MIN; + number = MB_STRLEN (t); + FREE (t); + } else { - number = 0; - - if (legal_number (name + 1, &arg_index)) /* ${#1} */ - { - t = get_dollar_var_value (arg_index); - if (t == 0 && unbound_vars_is_error) - return INTMAX_MIN; - number = MB_STRLEN (t); - FREE (t); - } + var = find_variable (name + 1); #if defined (ARRAY_VARS) - else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var))) + if (var && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var))) { if (assoc_p (var)) t = assoc_reference (assoc_cell (var), "0"); @@ -8198,14 +8198,13 @@ parameter_brace_expand_length (char *name) return INTMAX_MIN; number = MB_STRLEN (t); } + else #endif - /* Fast path for the common case of taking the length of a non-dynamic - scalar variable value. */ - else if ((var || (var = find_variable (name + 1))) && - invisible_p (var) == 0 && - array_p (var) == 0 && assoc_p (var) == 0 && - nameref_p (var) == 0 && - var->dynamic_value == 0) + /* Fast path for the common case of taking the length of a scalar + variable value. */ + if (var && invisible_p (var) == 0 && + array_p (var) == 0 && assoc_p (var) == 0 && + nameref_p (var) == 0) number = value_cell (var) ? MB_STRLEN (value_cell (var)) : 0; else if ((var = find_variable_last_nameref (name + 1, 0)) && nameref_p (var)) { diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index c8bef8dd..34b7f66b 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -10,4 +10,4 @@ export TMPDIR export BASH_TSTOUT=/tmp/xx rm -f ${BASH_TSTOUT} -/bin/sh "$@" +${THIS_SH} "$@" diff --git a/tests/alias.right b/tests/alias.right index d5c53f41..b6cc7ea6 100644 --- a/tests/alias.right +++ b/tests/alias.right @@ -5,6 +5,8 @@ alias: 0 quux hi declare -a m=([0]="x") +./alias.tests: line 66: alias: `\$': invalid alias name +./alias.tests: line 67: `\$': invalid alias name bar value bar diff --git a/tests/alias.tests b/tests/alias.tests index 14d3c63f..437378b0 100644 --- a/tests/alias.tests +++ b/tests/alias.tests @@ -62,6 +62,10 @@ alias L='m=("x")' L declare -p m +# invalid alias names generate errors +alias '\$'=xx +BASH_ALIASES['\$']=xx + ${THIS_SH} ./alias1.sub ${THIS_SH} ./alias2.sub ${THIS_SH} ./alias3.sub diff --git a/tests/arith-for.right b/tests/arith-for.right index 06127be8..542abeaf 100644 --- a/tests/arith-for.right +++ b/tests/arith-for.right @@ -84,3 +84,9 @@ bash: -c: line 1: syntax error: `(( i=0; i < 3; i++; 7 ))' 2 1 0 +43210 +ok1 +./arith-for.tests: line 133: ((: 7++ : arithmetic syntax error: operand expected (error token is "+ ") +./arith-for.tests: line 134: ((: i < 4/0: division by 0 (error token is "0") +./arith-for.tests: line 135: ((: i=2/0: division by 0 (error token is "0") +./arith-for.tests: line 137: ((: 7=4 : attempted assignment to non-variable (error token is "=4 ") diff --git a/tests/arith-for.tests b/tests/arith-for.tests index db913da5..47e7e5c5 100644 --- a/tests/arith-for.tests +++ b/tests/arith-for.tests @@ -126,3 +126,12 @@ echo for (( i = 4; ;i--)) ; do echo $i; if (( $i == 0 )); then break; fi; done for (( i = 4;;i--)) ; do echo $i; if (( $i == 0 )); then break; fi; done +i=4 ; for (( ;;i--)) ; do echo -n $i; if (( i == 0 )); then break; fi; done; echo + +# arithmetic for commands with expression errors + +for (( i=1; i < 4; 7++ )); do echo ok$i ; done +for (( i=2; i < 4/0; 7++ )); do echo whoops1 ; done +for (( i=2/0; i < 4; 7++ )); do echo whoops2 ; done + +for (( 7=4 ; 7 > 7; )); do echo whoops3; done diff --git a/tests/array.right b/tests/array.right index b16870dc..846e05f7 100644 --- a/tests/array.right +++ b/tests/array.right @@ -129,7 +129,9 @@ grep [ 123 ] * 6 7 9 5 length = 3 value = new1 new2 new3 -./array.tests: line 257: narray: unbound variable +./array.tests: line 256: syntax error near unexpected token `&' +./array.tests: line 256: `badarray=( metacharacters like & need to be quoted in compound assignments)' +./array.tests: line 260: narray: unbound variable ./array1.sub: line 1: syntax error near unexpected token `(' ./array1.sub: line 1: `printf "%s\n" -a a=(a 'b c')' ./array2.sub: line 1: declare: `[]=asdf': not a valid identifier @@ -156,10 +158,10 @@ for case if then else 12 14 16 18 20 4414758999202 aaa bbb -./array.tests: line 307: syntax error near unexpected token `<>' -./array.tests: line 307: `metas=( <> < > ! )' -./array.tests: line 308: syntax error near unexpected token `<>' -./array.tests: line 308: `metas=( [1]=<> [2]=< [3]=> [4]=! )' +./array.tests: line 310: syntax error near unexpected token `<>' +./array.tests: line 310: `metas=( <> < > ! )' +./array.tests: line 311: syntax error near unexpected token `<>' +./array.tests: line 311: `metas=( [1]=<> [2]=< [3]=> [4]=! )' abc 3 case 4 abc case if then else 5 diff --git a/tests/array.tests b/tests/array.tests index 714966ab..10f60555 100644 --- a/tests/array.tests +++ b/tests/array.tests @@ -252,6 +252,9 @@ barray=(new1 new2 new3) echo "length = ${#barray[@]}" echo "value = ${barray[*]}" +# the compound assignment syntax inherited from ksh93 has some quirks +badarray=( metacharacters like & need to be quoted in compound assignments) + # make sure the array code behaves correctly with respect to unset variables set -u ( echo ${#narray[4]} ) diff --git a/tests/builtins.right b/tests/builtins.right index e0b11ac4..94185909 100644 --- a/tests/builtins.right +++ b/tests/builtins.right @@ -91,6 +91,7 @@ FOO=BAR FOO=BAR hash: hash table empty 0 +no-newline AVAR foo in source.sub2, calling return @@ -145,11 +146,11 @@ AVAR foo declare -x foo="" declare -x FOO="\$\$" -./builtins.tests: line 228: declare: FOO: not found +./builtins.tests: line 239: declare: FOO: not found declare -x FOO="\$\$" ok ok -./builtins.tests: line 260: kill: 4096: invalid signal specification +./builtins.tests: line 271: kill: 4096: invalid signal specification 1 a\n\n\nb a @@ -291,6 +292,10 @@ u=rwx,g=rwx,o=rwx u=rwx,g=rwx,o=rwx u=rwx,g=rx,o=rx u=rwx,g=rx,o=rx +u=rwx,g=rx,o=rx +u=rwx,g=rx,o=rx +u=rwx,g=rx,o=rx +u=rwx,g=rx,o=rx hash: hash table empty ./builtins9.sub: line 19: hash: notthere: not found 1 @@ -308,4 +313,136 @@ builtin hash -p /nosuchdir/nosuchfile cat 0 found ./builtins9.sub: line 52: hash: /: Is a directory -./builtins.tests: line 290: exit: status: numeric argument required +builtin hash -p /nosuchfile cat +./builtins10.sub: line 17: help: -x: invalid option +help: usage: help [-dms] [pattern ...] +These shell commands are defined internally. Type `help' to see this list. +Type `help name' to find out more about the function `name'. +Use `info bash' to find out more about the shell in general. +Use `man -k' or `info' to find out more about commands not in this list. + +A star (*) next to a name means that the command is disabled. + + ! PIPELINE history [-c] [-d offset] [n] or hist> + job_spec [&] if COMMANDS; then COMMANDS; [ elif C> + (( expression )) jobs [-lnprs] [jobspec ...] or jobs > + . filename [arguments] kill [-s sigspec | -n signum | -sigs> + : let arg [arg ...] + [ arg... ] local [option] name[=value] ... + [[ expression ]] logout [n] + alias [-p] [name[=value] ... ] mapfile [-d delim] [-n count] [-O or> + bg [job_spec ...] popd [-n] [+N | -N] + bind [-lpsvPSVX] [-m keymap] [-f file> printf [-v var] format [arguments] + break [n] pushd [-n] [+N | -N | dir] + builtin [shell-builtin [arg ...]] pwd [-LP] + caller [expr] read [-Eers] [-a array] [-d delim] [> + case WORD in [PATTERN [| PATTERN]...)> readarray [-d delim] [-n count] [-O > + cd [-L|[-P [-e]]] [-@] [dir] readonly [-aAf] [name[=value] ...] o> + command [-pVv] command [arg ...] return [n] + compgen [-V varname] [-abcdefgjksuv] > select NAME [in WORDS ... ;] do COMM> + complete [-abcdefgjksuv] [-pr] [-DEI]> set [-abefhkmnptuvxBCEHPT] [-o optio> + compopt [-o|+o option] [-DEI] [name .> shift [n] + continue [n] shopt [-pqsu] [-o] [optname ...] + coproc [NAME] command [redirections] source filename [arguments] + declare [-aAfFgiIlnrtux] [name[=value> suspend [-f] + dirs [-clpv] [+N] [-N] test [expr] + disown [-h] [-ar] [jobspec ... | pid > time [-p] pipeline + echo [-neE] [arg ...] times + enable [-a] [-dnps] [-f filename] [na> trap [-Plp] [[action] signal_spec ..> + eval [arg ...] true + exec [-cl] [-a name] [command [argume> type [-afptP] name [name ...] + exit [n] typeset [-aAfFgiIlnrtux] name[=value> + export [-fn] [name[=value] ...] or ex> ulimit [-SHabcdefiklmnpqrstuvxPRT] [> + false umask [-p] [-S] [mode] + fc [-e ename] [-lnr] [first] [last] o> unalias [-a] name [name ...] + fg [job_spec] unset [-f] [-v] [-n] [name ...] + for NAME [in WORDS ... ] ; do COMMAND> until COMMANDS; do COMMANDS-2; done + for (( exp1; exp2; exp3 )); do COMMAN> variables - Names and meanings of so> + function name { COMMANDS ; } or name > wait [-fn] [-p var] [id ...] + getopts optstring name [arg ...] while COMMANDS; do COMMANDS-2; done + hash [-lr] [-p pathname] [-dt] [name > { COMMANDS ; } + help [-dms] [pattern ...] +help: help [-dms] [pattern ...] +shift - Shift positional parameters. +shift: shift [n] + Shift positional parameters. + + Rename the positional parameters $N+1,$N+2 ... to $1,$2 ... If N is + not given, it is assumed to be 1. + + Exit Status: + Returns success unless N is negative or greater than $#. +builtin: builtin [shell-builtin [arg ...]] +shift: shift [n] +Shell commands matching keyword `read*' + +read: read [-Eers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...] +readarray: readarray [-d delim] [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array] +readonly: readonly [-aAf] [name[=value] ...] or readonly -p +NAME + : - Null command. + +SYNOPSIS + : + +DESCRIPTION + Null command. + + No effect; the command does nothing. + + Exit Status: + Always succeeds. + +SEE ALSO + bash(1) + +IMPLEMENTATION + Copyright (C) 2022 Free Software Foundation, Inc. + +These shell commands are defined internally. Type `help' to see this list. +Type `help name' to find out more about the function `name'. +Use `info bash' to find out more about the shell in general. +Use `man -k' or `info' to find out more about commands not in this list. + +A star (*) next to a name means that the command is disabled. + + ! PIPELINE history [-c] [-d offset] [n] or hist> + job_spec [&] if COMMANDS; then COMMANDS; [ elif C> + (( expression )) jobs [-lnprs] [jobspec ...] or jobs > + . filename [arguments] kill [-s sigspec | -n signum | -sigs> + : let arg [arg ...] + [ arg... ] local [option] name[=value] ... + [[ expression ]] logout [n] + alias [-p] [name[=value] ... ] mapfile [-d delim] [-n count] [-O or> + bg [job_spec ...] popd [-n] [+N | -N] + bind [-lpsvPSVX] [-m keymap] [-f file> printf [-v var] format [arguments] + break [n] pushd [-n] [+N | -N | dir] + builtin [shell-builtin [arg ...]] pwd [-LP] + caller [expr] read [-Eers] [-a array] [-d delim] [> + case WORD in [PATTERN [| PATTERN]...)> readarray [-d delim] [-n count] [-O > + cd [-L|[-P [-e]]] [-@] [dir] readonly [-aAf] [name[=value] ...] o> + command [-pVv] command [arg ...] return [n] + compgen [-V varname] [-abcdefgjksuv] > select NAME [in WORDS ... ;] do COMM> + complete [-abcdefgjksuv] [-pr] [-DEI]> set [-abefhkmnptuvxBCEHPT] [-o optio> + compopt [-o|+o option] [-DEI] [name .> shift [n] + continue [n] shopt [-pqsu] [-o] [optname ...] + coproc [NAME] command [redirections] source filename [arguments] + declare [-aAfFgiIlnrtux] [name[=value> suspend [-f] + dirs [-clpv] [+N] [-N] test [expr] + disown [-h] [-ar] [jobspec ... | pid > time [-p] pipeline + echo [-neE] [arg ...] times + enable [-a] [-dnps] [-f filename] [na> trap [-Plp] [[action] signal_spec ..> + eval [arg ...] true + exec [-cl] [-a name] [command [argume> type [-afptP] name [name ...] + exit [n] typeset [-aAfFgiIlnrtux] name[=value> + export [-fn] [name[=value] ...] or ex> ulimit [-SHabcdefiklmnpqrstuvxPRT] [> + false umask [-p] [-S] [mode] + fc [-e ename] [-lnr] [first] [last] o> unalias [-a] name [name ...] + fg [job_spec] unset [-f] [-v] [-n] [name ...] + for NAME [in WORDS ... ] ; do COMMAND> until COMMANDS; do COMMANDS-2; done + for (( exp1; exp2; exp3 )); do COMMAN> variables - Names and meanings of so> + function name { COMMANDS ; } or name > wait [-fn] [-p var] [id ...] + getopts optstring name [arg ...] while COMMANDS; do COMMANDS-2; done + hash [-lr] [-p pathname] [-dt] [name > { COMMANDS ; } + help [-dms] [pattern ...] +./builtins.tests: line 316: exit: status: numeric argument required diff --git a/tests/builtins.tests b/tests/builtins.tests index a0924869..781c021c 100644 --- a/tests/builtins.tests +++ b/tests/builtins.tests @@ -71,6 +71,10 @@ for i in a b c; do done echo end +# check arguments to break and continue that exceed the loop level +for f in 1 2 3; do break -- 5; done +for f in 1 2 3; do continue -- 5; done + # check that `eval' re-evaluates arguments, but `builtin' and `command' do not AVAR='$BVAR' BVAR=foo @@ -145,11 +149,18 @@ command -p hash rm # check out source/. # sourcing a zero-length-file had better not be an error -rm -f /tmp/zero-length-file -cp /dev/null /tmp/zero-length-file -. /tmp/zero-length-file +rm -f $TMPDIR/zero-length-file-$$ +cp /dev/null $TMPDIR/zero-length-file-$$ +. $TMPDIR/zero-length-file-$$ echo $? -rm /tmp/zero-length-file +rm $TMPDIR/zero-length-file-$$ + +# and sourcing a file that doesn't end in a newline had better work too +SFILE=$TMPDIR/sourced-file-$$ +printf 'echo no-newline' > $SFILE +. $SFILE +rm -f $SFILE +unset -v SFILE AVAR=AVAR @@ -262,6 +273,13 @@ kill -l 4096 # kill -l NAME should return the signal number kill -l ${sigone/SIG/} +# kill -l NAME should work with and without the SIG prefix +x=$(kill -l INT) +y=$(kill -l SIGINT) + +[[ $x == $y ]] || echo kill -l error with SIG prefix +unset -v x y + # test behavior of shopt xpg_echo ${THIS_SH} ./builtins2.sub @@ -286,6 +304,14 @@ ${THIS_SH} ./builtins8.sub # hash tests ${THIS_SH} ./builtins9.sub +# help tests +${THIS_SH} ./builtins10.sub + +shift 0 # succeeds silently + +options=$(set -o -B 2>&1 | wc -l) +[[ $options -gt 3 ]] || echo 'set: bad -o option name parsing' + # this must be last -- it is a fatal error exit status diff --git a/tests/builtins10.sub b/tests/builtins10.sub new file mode 100644 index 00000000..4b9e6659 --- /dev/null +++ b/tests/builtins10.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 . +# +# have to run through sed or grep to filter out version information + +# let's exercise print-help +help -x + +help -- | sed 1d + +command help -s help +builtin help -d shift +shift --help +help -s builtin shift + +# this hasn't ever been very useful +help -s 'read*' + +help -m : | grep -v version + +LC_ALL=en_US.UTF-8 +help -- | sed 1d diff --git a/tests/builtins8.sub b/tests/builtins8.sub index 8b049c09..ffe9869b 100644 --- a/tests/builtins8.sub +++ b/tests/builtins8.sub @@ -63,3 +63,19 @@ umask -S umask 022 umask a+xr umask -S + +umask 022 +umask g+X +umask -S + +umask 022 +umask o+X +umask -S + +umask 022 +umask +X +umask -S + +umask 022 +umask g+x,o+x +umask -S diff --git a/tests/builtins9.sub b/tests/builtins9.sub index d8f6c97c..d1fcbec9 100644 --- a/tests/builtins9.sub +++ b/tests/builtins9.sub @@ -50,3 +50,10 @@ echo $? hash -r hash -p / root + +hash -r + +# assignment to BASH_CMDS[x] should be like hash -p +BASH_CMDS[cat]=/nosuchfile +hash -lt cat +hash -d cat diff --git a/tests/complete.right b/tests/complete.right index c8bf1dc0..500ec8f7 100644 --- a/tests/complete.right +++ b/tests/complete.right @@ -61,3 +61,230 @@ complete -d rmdir complete -f more complete -f -X '!*.+(gz|tgz)' gzcat ./complete.tests: line 123: complete: notthere: no completion specification +! +% +(( ... )) +. +: +[ +[[ ... ]] +alias +bg +bind +break +builtin +caller +case +cd +command +compgen +complete +compopt +continue +coproc +declare +dirs +disown +echo +enable +eval +exec +exit +export +false +fc +fg +for +for (( +function +getopts +hash +help +history +if +jobs +kill +let +local +logout +mapfile +popd +printf +pushd +pwd +read +readarray +readonly +return +select +set +shift +shopt +source +suspend +test +time +times +trap +true +type +typeset +ulimit +umask +unalias +unset +until +variables +wait +while +{ ... } +. +: +[ +alias +bg +bind +break +builtin +caller +cd +command +compgen +complete +compopt +continue +declare +dirs +disown +echo +enable +eval +exec +exit +export +false +fc +fg +getopts +hash +help +history +jobs +kill +let +local +logout +mapfile +popd +printf +pushd +pwd +read +readarray +readonly +return +set +shift +shopt +source +suspend +test +times +trap +true +type +typeset +ulimit +umask +unalias +unset +wait +. +: +[ +alias +bg +bind +break +builtin +caller +cd +command +compgen +complete +compopt +continue +declare +dirs +disown +echo +enable +eval +exec +exit +export +false +fc +fg +getopts +hash +help +history +jobs +kill +let +local +logout +mapfile +popd +printf +pushd +pwd +read +readarray +readonly +return +set +shift +shopt +source +suspend +test +times +trap +true +type +typeset +ulimit +umask +unalias +unset +wait +if +then +else +elif +fi +case +esac +for +select +while +until +do +done +in +function +time +{ +} +! +[[ +]] +coproc +./complete.tests: line 136: compgen: -r: invalid option +compgen: usage: compgen [-V varname] [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word] +./complete.tests: line 137: compgen: noaction: invalid action name +./complete.tests: line 138: compgen: -D: invalid option +compgen: usage: compgen [-V varname] [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word] +./complete.tests: line 140: compopt: nooption: invalid option name diff --git a/tests/complete.tests b/tests/complete.tests index 36a39833..e4c655ce 100644 --- a/tests/complete.tests +++ b/tests/complete.tests @@ -124,3 +124,17 @@ complete -r notthere complete -r complete + +# some random compgen topics + +compgen -A helptopic +command compgen -b +compgen -A enabled +compgen -k + +# and some errors +compgen -r +compgen -A noaction +compgen -D + +compopt -o nooption diff --git a/tests/comsub.right b/tests/comsub.right index 4a5039d6..5c856400 100644 --- a/tests/comsub.right +++ b/tests/comsub.right @@ -24,6 +24,7 @@ blank ---- blank ---- blank ---- blank ---- +func: v = comsub #esac a ok 1 diff --git a/tests/comsub.tests b/tests/comsub.tests index 5969f6ca..b4ae69b2 100644 --- a/tests/comsub.tests +++ b/tests/comsub.tests @@ -91,6 +91,15 @@ read << EOC Dir: ${BUILDDIR#<(echo a)/} EOC +# return in a comsub inside a shell function should abort the comsub +func() +{ + local v + v=$( echo comsub ; return ; echo after) + echo $FUNCNAME: v = $v +} +func + ${THIS_SH} ./comsub1.sub ${THIS_SH} ./comsub2.sub ${THIS_SH} ./comsub3.sub diff --git a/tests/dynvar.right b/tests/dynvar.right index e1344c60..fe795525 100644 --- a/tests/dynvar.right +++ b/tests/dynvar.right @@ -5,3 +5,11 @@ SECONDS ok EPOCHSECONDS ok EPOCHREALTIME ok echo $BASH_COMMAND +110 +111 +112 +113 +114 +./dynvar.tests: line 115: ((: LINENO / 0 : division by 0 (error token is "0 ") +0 +0 diff --git a/tests/dynvar.tests b/tests/dynvar.tests index ddf69ed1..690f1cc7 100644 --- a/tests/dynvar.tests +++ b/tests/dynvar.tests @@ -47,6 +47,11 @@ after=$SECONDS if (( $after > $before )); then echo SECONDS ok; fi unset before after +# do the best we can to test assignment to SECONDS +SECONDS=2 +sleep 1 +[[ $SECONDS -ge 10 ]] && echo 'SECONDS: bad value assignment' + # EPOCHSECONDS # not exact, but should work @@ -99,4 +104,23 @@ ${THIS_SH} -c 'echo $BASH_COMMAND' # FUNCNAME tested in func.tests # RANDOM tested in varenv.sh -# LINENO tested in dbg-support +# LINENO tested in dbg-support, misc additional tests here +arith_lineno() +{ + echo $LINENO + for f in 1 ; do echo $LINENO; done + for (( f=1 ; f < 2; f++ )); do echo $LINENO; done + echo $(( $LINENO )) + (( 1 == 1 )) && echo $LINENO + (( LINENO / 0 )) +} +arith_lineno + +# assignments to noassign variables are ignored +FUNCNAME=42 +echo $? $FUNCNAME + +GROUPS[0]=-1 +echo $? + +[[ ${GROUPS[0]} != -1 ]] || echo GROUPS noassign error diff --git a/tests/errors.right b/tests/errors.right index a95d0080..76bfbf32 100644 --- a/tests/errors.right +++ b/tests/errors.right @@ -13,110 +13,137 @@ unalias: usage: unalias [-a] name [name ...] ./errors.tests: line 48: `invalid-name': not a valid identifier ./errors.tests: line 50: `1': not a valid identifier ./errors.tests: line 51: `f\1': not a valid identifier +./errors.tests: line 55: `$1': not a valid identifier declare -fr func -./errors.tests: line 64: func: readonly function -./errors.tests: line 67: unset: -x: invalid option +./errors.tests: line 72: func: readonly function +./errors.tests: line 75: unset: -x: invalid option unset: usage: unset [-f] [-v] [-n] [name ...] -./errors.tests: line 70: unset: func: cannot unset: readonly function -./errors.tests: line 73: declare: func: readonly function -./errors.tests: line 77: declare: -a: invalid option -./errors.tests: line 78: declare: -i: invalid option -./errors.tests: line 82: unset: XPATH: cannot unset: readonly variable -./errors.tests: line 88: unset: cannot simultaneously unset a function and a variable -./errors.tests: line 91: declare: -z: invalid option +./errors.tests: line 78: unset: func: cannot unset: readonly function +./errors.tests: line 81: declare: func: readonly function +./errors.tests: line 85: declare: -a: invalid option +./errors.tests: line 86: declare: -i: invalid option +./errors.tests: line 90: unset: XPATH: cannot unset: readonly variable +./errors.tests: line 96: unset: cannot simultaneously unset a function and a variable +./errors.tests: line 99: declare: -z: invalid option declare: usage: declare [-aAfFgiIlnrtux] [name[=value] ...] or declare -p [-aAfFilnrtux] [name ...] -./errors.tests: line 93: declare: `-z': not a valid identifier -./errors.tests: line 94: declare: `/bin/sh': not a valid identifier -./errors.tests: line 98: declare: cannot use `-f' to make functions -./errors.tests: line 101: exec: -i: invalid option +./errors.tests: line 101: declare: `-z': not a valid identifier +./errors.tests: line 102: declare: `/bin/sh': not a valid identifier +./errors.tests: line 106: declare: cannot use `-f' to make functions +./errors.tests: line 109: exec: -i: invalid option exec: usage: exec [-cl] [-a name] [command [argument ...]] [redirection ...] -./errors.tests: line 105: export: XPATH: not a function -./errors.tests: line 108: break: only meaningful in a `for', `while', or `until' loop -./errors.tests: line 109: continue: only meaningful in a `for', `while', or `until' loop -./errors.tests: line 112: shift: label: numeric argument required -./errors.tests: line 117: shift: too many arguments -./errors.tests: line 123: let: expression expected -./errors.tests: line 126: local: can only be used in a function -./errors.tests: line 129: logout: not login shell: use `exit' -./errors.tests: line 132: hash: notthere: not found -./errors.tests: line 135: hash: -v: invalid option +./errors.tests: line 113: export: XPATH: not a function +./errors.tests: line 116: break: only meaningful in a `for', `while', or `until' loop +./errors.tests: line 117: continue: only meaningful in a `for', `while', or `until' loop +./errors.tests: line 120: shift: label: numeric argument required +./errors.tests: line 125: shift: too many arguments +./errors.tests: line 131: let: expression expected +./errors.tests: line 134: local: can only be used in a function +./errors.tests: line 137: logout: not login shell: use `exit' +./errors.tests: line 140: hash: notthere: not found +./errors.tests: line 143: hash: -v: invalid option hash: usage: hash [-lr] [-p pathname] [-dt] [name ...] -./errors.tests: line 139: hash: hashing disabled -./errors.tests: line 142: export: `AA[4]': not a valid identifier -./errors.tests: line 143: readonly: `AA[4]': not a valid identifier -./errors.tests: line 146: unset: [-2]: bad array subscript -./errors.tests: line 150: AA: readonly variable -./errors.tests: line 154: AA: readonly variable -./errors.tests: line 162: shift: 5: shift count out of range -./errors.tests: line 163: shift: -2: shift count out of range -./errors.tests: line 166: shopt: no_such_option: invalid shell option name -./errors.tests: line 167: shopt: no_such_option: invalid shell option name -./errors.tests: line 170: umask: 09: octal number out of range -./errors.tests: line 171: umask: `:': invalid symbolic mode character -./errors.tests: line 172: umask: `:': invalid symbolic mode operator -./errors.tests: line 175: umask: -i: invalid option +./errors.tests: line 147: hash: hashing disabled +./errors.tests: line 150: export: `AA[4]': not a valid identifier +./errors.tests: line 151: readonly: `AA[4]': not a valid identifier +./errors.tests: line 152: export: `invalid-var=4': not a valid identifier +./errors.tests: line 153: readonly: `invalid-var=4': not a valid identifier +./errors.tests: line 154: export: `invalid-var': not a valid identifier +./errors.tests: line 155: readonly: `invalid-var': not a valid identifier +./errors.tests: line 158: unset: [-2]: bad array subscript +./errors.tests: line 162: AA: readonly variable +./errors.tests: line 166: AA: readonly variable +./errors.tests: line 174: shift: 5: shift count out of range +./errors.tests: line 175: shift: -2: shift count out of range +./errors.tests: line 178: shopt: no_such_option: invalid shell option name +./errors.tests: line 179: shopt: no_such_option: invalid shell option name +./errors.tests: line 180: shopt: no_such_option: invalid option name +./errors.tests: line 183: umask: 09: octal number out of range +./errors.tests: line 184: umask: `:': invalid symbolic mode character +./errors.tests: line 185: umask: `:': invalid symbolic mode operator +./errors.tests: line 188: umask: -i: invalid option umask: usage: umask [-p] [-S] [mode] -./errors.tests: line 179: umask: `p': invalid symbolic mode character -./errors.tests: line 188: VAR: readonly variable -./errors.tests: line 191: declare: VAR: readonly variable -./errors.tests: line 192: declare: VAR: readonly variable -./errors.tests: line 194: declare: unset: not found -./errors.tests: line 197: VAR: readonly variable +./errors.tests: line 192: umask: `p': invalid symbolic mode character +./errors.tests: line 201: VAR: readonly variable +./errors.tests: line 204: declare: VAR: readonly variable +./errors.tests: line 205: declare: VAR: readonly variable +./errors.tests: line 207: declare: unset: not found +./errors.tests: line 210: 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 204: cd: HOME not set -./errors.tests: line 205: cd: /tmp/xyz.bash: No such file or directory -./errors.tests: line 207: cd: OLDPWD not set -./errors.tests: line 208: cd: /bin/sh: Not a directory -./errors.tests: line 210: cd: /tmp/cd-notthere: No such file or directory -./errors.tests: line 213: .: filename argument required +./errors.tests: line 217: cd: HOME not set +./errors.tests: line 218: cd: /tmp/xyz.bash: No such file or directory +./errors.tests: line 220: cd: OLDPWD not set +./errors.tests: line 221: cd: /bin/sh: Not a directory +./errors.tests: line 223: cd: /tmp/cd-notthere: No such file or directory +./errors.tests: line 225: cd: too many arguments +bash: line 1: PWD: readonly variable +1 +./errors.tests: line 230: .: filename argument required .: usage: . filename [arguments] -./errors.tests: line 214: source: filename argument required +./errors.tests: line 231: source: filename argument required source: usage: source filename [arguments] -./errors.tests: line 217: .: -i: invalid option +./errors.tests: line 234: .: -i: invalid option .: usage: . filename [arguments] -./errors.tests: line 220: set: -q: invalid option +./errors.tests: line 237: set: -q: invalid option set: usage: set [-abefhkmnptuvxBCEHPT] [-o option-name] [--] [-] [arg ...] -./errors.tests: line 223: enable: sh: not a shell builtin -./errors.tests: line 223: enable: bash: not a shell builtin -./errors.tests: line 226: shopt: cannot set and unset shell options simultaneously -./errors.tests: line 229: read: var: invalid timeout specification -./errors.tests: line 232: read: `/bin/sh': not a valid identifier -./errors.tests: line 235: VAR: readonly variable -./errors.tests: line 238: readonly: -x: invalid option +./errors.tests: line 240: enable: sh: not a shell builtin +./errors.tests: line 240: enable: bash: not a shell builtin +./errors.tests: line 243: shopt: cannot set and unset shell options simultaneously +./errors.tests: line 246: read: -x: invalid option +read: usage: read [-Eers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...] +./errors.tests: line 249: read: var: invalid timeout specification +./errors.tests: line 252: read: `/bin/sh': not a valid identifier +./errors.tests: line 253: read: `/bin/sh': not a valid identifier +./errors.tests: line 256: VAR: readonly variable +./errors.tests: line 259: read: XX: invalid file descriptor specification +./errors.tests: line 260: read: 42: invalid file descriptor: Bad file descriptor +./errors.tests: line 263: mapfile: XX: invalid file descriptor specification +./errors.tests: line 264: mapfile: 42: invalid file descriptor: Bad file descriptor +./errors.tests: line 268: mapfile: empty array variable name +./errors.tests: line 269: mapfile: `invalid-var': not a valid identifier +./errors.tests: line 272: readonly: -x: invalid option readonly: usage: readonly [-aAf] [name[=value] ...] or readonly -p -./errors.tests: line 241: eval: -i: invalid option +./errors.tests: line 275: eval: -i: invalid option eval: usage: eval [arg ...] -./errors.tests: line 242: command: -i: invalid option +./errors.tests: line 276: command: -i: invalid option command: usage: command [-pVv] command [arg ...] -./errors.tests: line 245: /bin/sh + 0: arithmetic syntax error: operand expected (error token is "/bin/sh + 0") -./errors.tests: line 246: /bin/sh + 0: arithmetic syntax error: operand expected (error token is "/bin/sh + 0") -./errors.tests: line 249: trap: NOSIG: invalid signal specification -./errors.tests: line 252: trap: -s: invalid option +./errors.tests: line 279: /bin/sh + 0: arithmetic syntax error: operand expected (error token is "/bin/sh + 0") +./errors.tests: line 280: /bin/sh + 0: arithmetic syntax error: operand expected (error token is "/bin/sh + 0") +./errors.tests: line 283: trap: NOSIG: invalid signal specification +./errors.tests: line 286: trap: -s: invalid option trap: usage: trap [-Plp] [[action] signal_spec ...] -./errors.tests: line 258: return: can only `return' from a function or sourced script -./errors.tests: line 262: break: 0: loop count out of range -./errors.tests: line 266: continue: 0: loop count out of range -./errors.tests: line 271: builtin: bash: not a shell builtin -./errors.tests: line 275: bg: no job control -./errors.tests: line 276: fg: no job control -./errors.tests: line 279: kill: -s: option requires an argument -./errors.tests: line 281: kill: S: invalid signal specification -./errors.tests: line 283: kill: `': not a pid or valid job spec +./errors.tests: line 292: return: can only `return' from a function or sourced script +./errors.tests: line 296: break: 0: loop count out of range +./errors.tests: line 300: continue: 0: loop count out of range +./errors.tests: line 305: builtin: bash: not a shell builtin +./errors.tests: line 309: bg: no job control +./errors.tests: line 310: fg: no job control +./errors.tests: line 313: kill: -s: option requires an argument +./errors.tests: line 315: kill: S: invalid signal specification +./errors.tests: line 317: 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 288: set: trackall: invalid option name -./errors.tests: line 289: set: -q: invalid option +./errors.tests: line 321: kill: SIGBAD: invalid signal specification +./errors.tests: line 323: kill: BAD: invalid signal specification +./errors.tests: line 325: kill: @12: arguments must be process or job IDs +./errors.tests: line 328: unset: BASH_LINENO: cannot unset +./errors.tests: line 328: unset: BASH_SOURCE: cannot unset +./errors.tests: line 331: set: trackall: invalid option name +./errors.tests: line 332: set: -q: invalid option set: usage: set [-abefhkmnptuvxBCEHPT] [-o option-name] [--] [-] [arg ...] -./errors.tests: line 290: set: -i: invalid option +./errors.tests: line 333: set: -i: invalid option set: usage: set [-abefhkmnptuvxBCEHPT] [-o option-name] [--] [-] [arg ...] -./errors.tests: line 294: xx: readonly variable +./errors.tests: line 337: xx: readonly variable 1 ./errors1.sub: line 14: .: -i: invalid option .: usage: . filename [arguments] ./errors1.sub: line 22: shift: -4: shift count out of range +./errors1.sub: line 23: shift: -4: shift count out of range ./errors1.sub: line 27: break: -1: loop count out of range +./errors1.sub: line 28: continue: -1: loop count out of range +./errors1.sub: line 29: break: -5: loop count out of range +./errors1.sub: line 30: continue: -5: loop count out of range after f ./errors2.sub: line 3: ${$NO_SUCH_VAR}: bad substitution 1 @@ -200,6 +227,7 @@ after non-special builtin: 0 after special builtin: 0 ./errors7.sub: line 27: x: readonly variable ./errors7.sub: line 29: x: readonly variable +./errors7.sub: line 32: v: readonly variable ./errors7.sub: line 21: x: readonly variable after no such command: 1 ./errors7.sub: line 23: x: readonly variable @@ -207,6 +235,7 @@ 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 +./errors7.sub: line 32: v: readonly variable ./errors8.sub: eval: line 7: syntax error: unexpected end of file ok 1 ./errors8.sub: line 8: v: readonly variable @@ -238,4 +267,4 @@ sh: line 1: unset: `a-b': not a valid identifier sh: line 1: /nosuchfile: No such file or directory sh: line 1: trap: SIGNOSIG: invalid signal specification after trap -./errors.tests: line 333: `!!': not a valid identifier +./errors.tests: line 376: `!!': not a valid identifier diff --git a/tests/errors.tests b/tests/errors.tests index 17354dc9..5f45cfd3 100644 --- a/tests/errors.tests +++ b/tests/errors.tests @@ -50,6 +50,14 @@ select invalid-name in a b c; do echo $REPLY; done (set -o posix ; select 1 in a b c; do echo $REPLY; done; echo after posix select) (set -o posix ; select f\1 in a b c ; do echo $REPLY ; done ; echo after posix select 2) +# even in functions +bad-select() +{ + select $1 in a b c ; do echo $REPLY ; done +} +bad-select 'a b' +unset -f bad-select + # try to rebind a read-only function func() { @@ -141,6 +149,10 @@ hash -p ${THIS_SH} ${THIS_SH##*/} # bad identifiers to declare/readonly/export export AA[4] readonly AA[4] +export invalid-var=4 +readonly invalid-var=4 +export invalid-var +readonly invalid-var declare -a AA unset AA[-2] @@ -165,6 +177,7 @@ shift -2 # bad shell options shopt -s no_such_option shopt no_such_option +shopt -s -o no_such_option # non-octal digits for umask and other errors umask 09 @@ -208,6 +221,10 @@ cd - cd /bin/sh # error - not a directory OLDPWD=/tmp/cd-notthere cd - +# too many arguments +cd one two three +# cd doesn't like it if PWD is readonly +${THIS_SH} -c 'readonly PWD ; cd / ; echo $?' bash # various `source/.' errors . @@ -225,15 +242,32 @@ enable sh bash # try to set and unset shell options simultaneously shopt -s -u checkhash +# error +read -x + # this is an error -- bad timeout spec read -t var < /dev/null # try to read into an invalid identifier read /bin/sh < /dev/null +read A /bin/sh < /dev/null # try to read into a readonly variable read VAR < /dev/null +# invalid file descriptor +read -u XX < /dev/null +read -u 42 < /dev/null + +# same with mapfile +mapfile -u XX A < /dev/null +mapfile -u 42 A < /dev/null +unset -v A + +# invalid identifier arguments to mapfile +mapfile '' argv[1] = argv[1] = argv[1] = <10> +argv[1] = <5> +argv[1] = <5> argv[1] = argv[1] = argv[1] = diff --git a/tests/exp.tests b/tests/exp.tests index 61a39d3b..8dc0a601 100644 --- a/tests/exp.tests +++ b/tests/exp.tests @@ -237,6 +237,15 @@ POSIX=/usr/posix expect '<10>' recho ${#POSIX} +# this was a problem through bash-5.2 -- it would skip random numbers because +# of multiple calls to find_variable +RANDOM=42 +expect '<5>' +recho ${#RANDOM} # 17772 +declare -i RANDOM=42 +expect '<5>' +recho ${#RANDOM} # 17772 + # remove shortest trailing match x=file.c expect '' diff --git a/tests/func.right b/tests/func.right index b5d6f342..f5341351 100644 --- a/tests/func.right +++ b/tests/func.right @@ -166,6 +166,7 @@ after FUNCNEST unset: f = 201 ./func4.sub: line 23: foo: maximum function nesting level exceeded (20) 1 after FUNCNEST assign: f = 38 +./func5.sub: line 31: `sys$read': not a valid identifier 11111 () { printf "FUNCNAME: %s\n" $FUNCNAME @@ -189,4 +190,5 @@ break () echo FUNCNAME: $FUNCNAME } FUNCNAME: break +./func5.sub: line 54: `break': is a special builtin 5 diff --git a/tests/func5.sub b/tests/func5.sub index 7ec19396..ef43de21 100644 --- a/tests/func5.sub +++ b/tests/func5.sub @@ -12,6 +12,8 @@ # along with this program. If not, see . # +# these are ok + function a=2 { printf "FUNCNAME: %s\n" $FUNCNAME @@ -22,6 +24,12 @@ function 11111 printf "FUNCNAME: %s\n" $FUNCNAME } +# but this is still not +function sys$read +{ + printf "FUNCNAME: %s\n" $FUNCNAME +} + declare -f set -o posix declare -f @@ -36,3 +44,11 @@ break() type break \break +unset -f break + +# but in posix mode, declaring such a function is an error +set -o posix +break() +{ + echo FUNCNAME: $FUNCNAME +} diff --git a/tests/getopts.right b/tests/getopts.right index 599d830a..f5a5262a 100644 --- a/tests/getopts.right +++ b/tests/getopts.right @@ -66,3 +66,5 @@ OPTARG = x = ? unset x = ? declare -r RO="foo" declare -r RO="foo" +./getopts10.sub: line 33: V: readonly variable +1 diff --git a/tests/getopts10.sub b/tests/getopts10.sub index 49b2bfe9..a761bd34 100644 --- a/tests/getopts10.sub +++ b/tests/getopts10.sub @@ -28,3 +28,9 @@ typeset -p RO getopts x x typeset -p RO + +readonly V +getopts x V +echo $? + + diff --git a/tests/glob-bracket.tests b/tests/glob-bracket.tests index 34580ebb..057ffeb2 100644 --- a/tests/glob-bracket.tests +++ b/tests/glob-bracket.tests @@ -305,4 +305,5 @@ check 'a\' 'a\' "$yes" cd $ORIG_DIR +enable -d strmatch # just testing exit 0 diff --git a/tests/glob10.sub b/tests/glob10.sub index 7c14c0d2..1ee8046e 100644 --- a/tests/glob10.sub +++ b/tests/glob10.sub @@ -15,7 +15,7 @@ # test basic behavior of globskipdots TDIR=/tmp/dotglob-$$ -{ mkdir $TDIR && cd $TDIR; } || exit 1 +{ mkdir $TDIR && cd -L $TDIR; } || exit 1 touch a b aa bb .a .b .aa .bb diff --git a/tests/glob8.sub b/tests/glob8.sub index dca54fcc..877c8bd1 100644 --- a/tests/glob8.sub +++ b/tests/glob8.sub @@ -15,7 +15,7 @@ TESTDIR=${TMPDIR}/glob-test-$$ mkdir ${TESTDIR} -cd $TESTDIR || { +cd -L $TESTDIR || { echo "$TESTDIR: cannot cd" >&2 exit 1 } diff --git a/tests/history.right b/tests/history.right index 2f55d330..7402bacd 100644 --- a/tests/history.right +++ b/tests/history.right @@ -140,6 +140,8 @@ three one two three +(exit 42) +42 5.3 echo ${BASH_VERSION%\.*} 5.3 @@ -341,3 +343,14 @@ $ 1 $ 2 $ exit 0 +a +b +c +d + 1 echo a + 2 echo c + 3 echo d + 4 history -d 2 + 5 history +./history8.sub: line 15: history: 72: history position out of range +./history8.sub: line 16: history: -72: history position out of range diff --git a/tests/history.tests b/tests/history.tests index 2bff8811..4cc078dd 100644 --- a/tests/history.tests +++ b/tests/history.tests @@ -132,3 +132,4 @@ ${THIS_SH} ./history4.sub ${THIS_SH} ./history5.sub ${THIS_SH} ./history6.sub ${THIS_SH} ./history7.sub +${THIS_SH} ./history8.sub diff --git a/tests/history1.sub b/tests/history1.sub index b67a0efa..eb8b4f59 100644 --- a/tests/history1.sub +++ b/tests/history1.sub @@ -26,3 +26,8 @@ three history fc -s cat + +# try re-executing a failed command, check the exit status +(exit 42) +fc -s -1 +echo $? diff --git a/tests/history8.sub b/tests/history8.sub new file mode 100644 index 00000000..77659fc6 --- /dev/null +++ b/tests/history8.sub @@ -0,0 +1,16 @@ +trap 'rm -f "$OUT"' 0 1 2 3 6 15 + +HISTFILE=$TMPDIR/fchist-$$ ; OUT=$HISTFILE +unset HISTIGNORE HISTCONTROL +set -o history + +echo a +echo b +echo c +echo d + +history -d 2 +history + +history -d 72 +history -d -72 diff --git a/tests/invocation.right b/tests/invocation.right index 99a82c45..885a4df1 100644 --- a/tests/invocation.right +++ b/tests/invocation.right @@ -69,8 +69,20 @@ GNU long options: Shell options: -ilrsD or -c command or -O shopt_option (invocation only) -abefhkmnptuvxBCEHPT or -o option -this-bash +this-bash this-bash $- for -c includes c +bash: line 0: badopt: invalid shell option name +checkwinsize:cmdhist:complete_fullquote:extquote:force_fignore:globasciiranges:globskipdots:hostcomplete:interactive_comments:patsub_replacement:progcomp:promptvars:sourcepath +checkhash:checkwinsize:cmdhist:complete_fullquote:extquote:force_fignore:globasciiranges:globskipdots:hostcomplete:interactive_comments:patsub_replacement:progcomp:promptvars:sourcepath +cmdhist:complete_fullquote:extquote:force_fignore:globasciiranges:globskipdots:hostcomplete:interactive_comments:patsub_replacement:progcomp:promptvars:sourcepath +./invocation1.sub: line 40: BASHOPTS: readonly variable +braceexpand:hashall:interactive-comments +braceexpand:hashall:interactive-comments +hashall:interactive-comments +hashall:interactive-comments +braceexpand:hashall:interactive-comments:noglob +braceexpand:hashall:interactive-comments:noglob +./invocation2.sub: line 50: SHELLOPTS: readonly variable a a bad-interp diff --git a/tests/invocation.tests b/tests/invocation.tests index f3952892..84c908ea 100644 --- a/tests/invocation.tests +++ b/tests/invocation.tests @@ -16,8 +16,6 @@ # invocation modes and errors -export BASH_ARGV0=this-bash - ${THIS_SH} . #${THIS_SH} --version -c 'exit 0' bash @@ -29,10 +27,17 @@ ${THIS_SH} --badopt |& sed 's|^.*/bash|bash|' ${THIS_SH} --initfile |& sed 's|^.*/bash|bash|' ${THIS_SH} -q |& sed 's|^.*/bash|bash|' -${THIS_SH} -c 'echo $0' +export BASH_ARGV0=this-bash +${THIS_SH} -c 'echo $0 $BASH_ARGV0' +unset BASH_ARGV0 { ${THIS_SH} -c 'echo $-' bash | grep c >/dev/null; } && echo '$- for -c includes c' +# BASHOPTS +${THIS_SH} ./invocation1.sub +# SHELLOPTS +${THIS_SH} ./invocation2.sub + : ${TMPDIR:=/tmp} TDIR=$TMPDIR/invocation-$$ mkdir $TDIR || exit 1 diff --git a/tests/invocation1.sub b/tests/invocation1.sub new file mode 100644 index 00000000..ea3d68cc --- /dev/null +++ b/tests/invocation1.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 . +# +set +o posix +shopt -u xpg_echo + +# check $BASHOPTS inheritance +# the first should be an error +${THIS_SH} -O checkhash -O badopt -c 'echo $BASHOPTS' bash 2>&1 | sed 's|^.*/bash|bash|' +# this should reflect the default set of options +${THIS_SH} -c 'echo $BASHOPTS' +# now let's turn one of them on (checkhash is not enabled by default) +${THIS_SH} -O checkhash -c 'echo $BASHOPTS' bash +# let's turn one of them off +${THIS_SH} +O checkwinsize -c 'echo $BASHOPTS' bash + +# turn on a non-default option +shopt -s checkhash +export BASHOPTS +# and make sure the child shell sees it enabled +if ${THIS_SH} -c 'echo $BASHOPTS' | grep checkhash >/dev/null 2>&1; then + : +else + echo 'BASHOPTS: checkhash not inherited correctly' +fi +shopt -u checkhash +export -n BASHOPTS + +# but assigning to BASHOPTS is an error +BASHOPTS=$BASHOPTS diff --git a/tests/invocation2.sub b/tests/invocation2.sub new file mode 100644 index 00000000..05de4019 --- /dev/null +++ b/tests/invocation2.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 . +# + +set +o posix +shopt -u xpg_echo + +echo $SHELLOPTS +set +B # on by default +# shouldn't appear +echo $SHELLOPTS | grep braceexpand +export SHELLOPTS +# but it will appear here because it's enabled by default +${THIS_SH} -c 'echo $SHELLOPTS' + +# turn off an option that's on by default +${THIS_SH} +B -c 'echo $SHELLOPTS' +${THIS_SH} +o braceexpand -c 'echo $SHELLOPTS' + +# turn on an option that's off by default +if ${THIS_SH} -f -c 'echo $SHELLOPTS' | grep noglob 2>&1; then + : +else + echo 'SHELLOPTS: noglob not inherited correctly' +fi + +# in a different way +set -o noglob +if ${THIS_SH} -c 'echo $SHELLOPTS' | grep noglob 2>&1; then + : +else + echo 'SHELLOPTS: noglob not inherited correctly' +fi + +# restore default state +set -o braceexpand +set +o noglob + +# but assigning to SHELLOPTS is an error; have to use set -o/+o +SHELLOPTS=$SHELLOPTS diff --git a/tests/jobs.right b/tests/jobs.right index 0510e044..9a12a884 100644 --- a/tests/jobs.right +++ b/tests/jobs.right @@ -33,17 +33,19 @@ i killed it 2: ok 3 127 ./jobs5.sub: line 71: declare: wpid: not found +./jobs5.sub: line 74: wait: `invalid-varname': not a valid identifier +./jobs5.sub: line 76: wait: WV: cannot unset: readonly variable child1 exit status 0 [1]+ Running sleep 20 & ./jobs7.sub: line 5: fg: no current jobs [1]+ Running sleep 20 & 0 -./jobs.tests: line 40: wait: %1: no such job -./jobs.tests: line 45: fg: no job control +./jobs.tests: line 42: wait: %1: no such job +./jobs.tests: line 47: fg: no job control wait-for-pid wait-errors -./jobs.tests: line 58: wait: `1-1': not a pid or valid job spec -./jobs.tests: line 59: wait: `-4': not a pid or valid job spec +./jobs.tests: line 60: wait: `1-1': not a pid or valid job spec +./jobs.tests: line 61: wait: `-4': not a pid or valid job spec wait-for-background-pids async list wait-for-background-pids async list wait for child @@ -52,7 +54,7 @@ wait-when-no-children posix jobs output [1]+ Done sleep 1 wait-for-job -./jobs.tests: line 84: wait: %2: no such job +./jobs.tests: line 86: wait: %2: no such job 127 async list wait-for-job forked @@ -65,19 +67,20 @@ sleep 2 fg-bg 4 sleep 2 fg-bg 5 -./jobs.tests: line 111: fg: %2: no such job -./jobs.tests: line 112: bg: job 1 already in background +./jobs.tests: line 113: fg: %2: no such job +./jobs.tests: line 114: bg: job 1 already in background fg-bg 6 -./jobs.tests: line 119: fg: -s: invalid option +./jobs.tests: line 121: fg: -s: invalid option fg: usage: fg [job_spec] -./jobs.tests: line 120: bg: -s: invalid option +./jobs.tests: line 122: bg: -s: invalid option bg: usage: bg [job_spec ...] -./jobs.tests: line 125: disown: -s: invalid option +./jobs.tests: line 127: disown: -s: invalid option disown: usage: disown [-h] [-ar] [jobspec ... | pid ...] -./jobs.tests: line 129: disown: %1: no such job -./jobs.tests: line 132: disown: %2: no such job +./jobs.tests: line 131: disown: %1: no such job +./jobs.tests: line 134: disown: %2: no such job +./jobs.tests: line 137: disown: @12: no such job wait-for-non-child -./jobs.tests: line 135: wait: pid 1 is not a child of this shell +./jobs.tests: line 140: wait: pid 1 is not a child of this shell 127 3 -- 1 2 3 -- 1 - 2 - 3 [1] Running sleep 300 & @@ -87,8 +90,8 @@ running jobs: [1] Running sleep 300 & [2]- Running sleep 350 & [3]+ Running sleep 400 & -./jobs.tests: line 152: kill: %4: no such job -./jobs.tests: line 154: jobs: %4: no such job +./jobs.tests: line 157: kill: %4: no such job +./jobs.tests: line 159: jobs: %4: no such job current job: [3]+ Running sleep 400 & previous job: diff --git a/tests/jobs.tests b/tests/jobs.tests index dacdc15d..605449aa 100644 --- a/tests/jobs.tests +++ b/tests/jobs.tests @@ -32,6 +32,8 @@ ${THIS_SH} ./jobs5.sub ${THIS_SH} ./jobs6.sub ${THIS_SH} ./jobs7.sub +# more disown -h tests +${THIS_SH} ./jobs8.sub jobs echo $? @@ -131,6 +133,9 @@ disown %1 # this, however, is an error disown %2 +# this is definitely an error +disown -h @12 + echo wait-for-non-child wait 1 echo $? diff --git a/tests/jobs5.sub b/tests/jobs5.sub index e348f2e2..23e1b1db 100644 --- a/tests/jobs5.sub +++ b/tests/jobs5.sub @@ -69,3 +69,8 @@ echo $wpid $? jobs wait -p wpid declare -p wpid + +# let's check errors like with other builtins that take variable names +wait -p invalid-varname +readonly WV +wait -p WV diff --git a/tests/jobs8.sub b/tests/jobs8.sub new file mode 100644 index 00000000..8bb21bd6 --- /dev/null +++ b/tests/jobs8.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 . +# + +# tests of disown -h + +set -m + +sleep 1& +sleep 1& +sleep 1& + +disown -ah + +sleep 1& +sleep 1& +sleep 1& + +disown -rh diff --git a/tests/new-exp.right b/tests/new-exp.right index 355abc4b..8aa4b324 100644 --- a/tests/new-exp.right +++ b/tests/new-exp.right @@ -59,6 +59,7 @@ argv[1] = <4> argv[1] = argv[1] = argv[1] = +./new-exp.tests: line 189: bad-var: invalid variable name argv[1] = argv[2] = argv[3] = @@ -66,8 +67,8 @@ argv[4] = argv[1] = argv[2] = argv[3] = -./new-exp.tests: line 197: ABX: unbound variable -./new-exp.tests: line 201: $6: cannot assign in this way +./new-exp.tests: line 202: ABX: unbound variable +./new-exp.tests: line 206: $6: cannot assign in this way argv[1] = argv[1] = argv[1] = @@ -176,7 +177,7 @@ a ./new-exp2.sub: line 62: 1111111111111111111111: command not found argv[1] = <6> -./new-exp.tests: line 302: ${#:}: bad substitution +./new-exp.tests: line 307: ${#:}: bad substitution argv[1] = <'> argv[1] = <"> argv[1] = <"hello"> @@ -411,13 +412,13 @@ argv[6] = argv[7] = argv[8] = argv[9] = -./new-exp.tests: line 520: $9: unbound variable -./new-exp.tests: line 521: 9: unbound variable -./new-exp.tests: line 522: UNSET: unbound variable -./new-exp.tests: line 523: UNSET: unbound variable -./new-exp.tests: line 524: UNSET: unbound variable -./new-exp.tests: line 525: UNSET: unbound variable -./new-exp.tests: line 526: UNSET: unbound variable +./new-exp.tests: line 525: $9: unbound variable +./new-exp.tests: line 526: 9: unbound variable +./new-exp.tests: line 527: UNSET: unbound variable +./new-exp.tests: line 528: UNSET: unbound variable +./new-exp.tests: line 529: UNSET: unbound variable +./new-exp.tests: line 530: UNSET: unbound variable +./new-exp.tests: line 531: UNSET: unbound variable argv[1] = <5> argv[1] = <#> argv[1] = <#> @@ -464,7 +465,7 @@ Case05---3---A:B:C--- Case06---1---A B C::--- Case07---3---A:B:C--- Case08---3---A:B:C--- -./new-exp.tests: line 546: ${$(($#-1))}: bad substitution +./new-exp.tests: line 551: ${$(($#-1))}: bad substitution argv[1] = argv[2] = argv[3] = @@ -481,8 +482,8 @@ argv[1] = argv[1] = argv[2] = argv[1] = <> -./new-exp.tests: line 565: $(($# - 2)): substring expression < 0 -./new-exp.tests: line 567: -2: substring expression < 0 +./new-exp.tests: line 570: $(($# - 2)): substring expression < 0 +./new-exp.tests: line 572: -2: substring expression < 0 argv[1] = argv[2] = argv[3] = diff --git a/tests/new-exp.tests b/tests/new-exp.tests index c542313f..cabaf7b0 100644 --- a/tests/new-exp.tests +++ b/tests/new-exp.tests @@ -184,6 +184,11 @@ recho ${a-$z} expect nothing recho ${!1-$z} +expect an error +v=bad-var +echo ${!v} +unset -v v + set -- a 'b c' d unset foo foo=@ diff --git a/tests/printf.right b/tests/printf.right index e99d04a7..b5765c91 100644 --- a/tests/printf.right +++ b/tests/printf.right @@ -13,6 +13,9 @@ unquoted unquoted quoted unquoted quoted this\&that +echo a\\;ls +echo a\'\;ls +echo 'a'\''b'\;ls 1 2 3 4 5 onestring 0 0 0 onestring 0 0 0.00 @@ -30,7 +33,7 @@ A7 --\"abcd\"-- --\'abcd\'-- --a\x-- -./printf.tests: line 95: printf: missing hex digit for \x +./printf.tests: line 105: printf: missing hex digit for \x --\x-- ---- ---- @@ -91,12 +94,12 @@ A7 26 26 26 -./printf.tests: line 219: printf: `%10': missing format character -./printf.tests: line 220: printf: `M': invalid format character -ab./printf.tests: line 223: printf: `y': invalid format character -./printf.tests: line 226: printf: GNU: invalid number +./printf.tests: line 229: printf: `%10': missing format character +./printf.tests: line 230: printf: `M': invalid format character +ab./printf.tests: line 233: printf: `y': invalid format character +./printf.tests: line 236: printf: GNU: invalid number 0 -./printf.tests: line 227: printf: GNU: invalid number +./printf.tests: line 237: printf: GNU: invalid number 0 - (foo )(bar ) @@ -149,6 +152,10 @@ b xx xx < >< > +./printf.tests: line 341: printf: 9223372036854775825: Result too large +9223372036854775807 +./printf.tests: line 342: printf: -9223372036854775815: Result too large +-9223372036854775808 one one\ctwo 4\.2 @@ -161,6 +168,8 @@ unquoted unquoted quoted unquoted quoted this\&that +'no-quotes-needed' +'quotes;needed' 1 2 3 4 5 onestring 0 0 0 onestring 0 0 0.00 @@ -174,7 +183,7 @@ A7 --\"abcd\"-- --\'abcd\'-- --a\x-- -./printf1.sub: line 107: printf: missing hex digit for \x +./printf1.sub: line 111: printf: missing hex digit for \x --\x-- ---- ---- @@ -235,12 +244,12 @@ A7 26 26 26 -./printf1.sub: line 293: printf: `%10': missing format character -./printf1.sub: line 294: printf: `M': invalid format character -./printf1.sub: line 297: printf: `y': invalid format character -./printf1.sub: line 300: printf: GNU: invalid number +./printf1.sub: line 297: printf: `%10': missing format character +./printf1.sub: line 298: printf: `M': invalid format character +./printf1.sub: line 301: printf: `y': invalid format character +./printf1.sub: line 304: printf: GNU: invalid number 0 -./printf1.sub: line 302: printf: GNU: invalid number +./printf1.sub: line 306: printf: GNU: invalid number 0 - (foo )(bar ) diff --git a/tests/printf.tests b/tests/printf.tests index 04a1e481..ee668cc9 100644 --- a/tests/printf.tests +++ b/tests/printf.tests @@ -60,6 +60,16 @@ printf "%s%10q\n" unquoted quoted printf "%q\n" 'this&that' +# %Q is like %q but treats the precision differently +S="a'b" +S1="${S@Q}" +T=';ls' + +printf 'echo %.2q%q\n' "$S" "$T" +printf 'echo %.2Q%Q\n' "$S" "$T" # note the difference +# a different way to do it +printf 'echo %.*s%q\n' ${#S1} "$S1" "$T" + # make sure the format string is reused to use up arguments printf "%d " 1 2 3 4 5; printf "\n" @@ -324,6 +334,13 @@ printf -v var "%b" @(hugo); echo "x${var}x" # make sure that missing arguments are always handled like the empty string printf "<%3s><%3b>\n" +# let's test some out-of-range integer errors for POSIX-specified behavior +TOOBIG=9223372036854775825 +TOOSMALL=-9223372036854775815 + +printf '%d\n' "$TOOBIG" +printf '%d\n' "$TOOSMALL" + # tests variable assignment with -v ${THIS_SH} ./printf1.sub ${THIS_SH} ./printf2.sub diff --git a/tests/printf1.sub b/tests/printf1.sub index 2cbbc6a6..7a18a5c6 100644 --- a/tests/printf1.sub +++ b/tests/printf1.sub @@ -60,6 +60,10 @@ printf "%s" "$vv" printf -v vv "%q\n" 'this&that' printf "%s" "$vv" +# altform with %q will force single-quoting +printf -v vv '%#q\n' no-quotes-needed 'quotes;needed' +printf "%s" "$vv" + # make sure the format string is reused to use up arguments printf -v vv "%d " 1 2 3 4 5 printf "%s" "$vv" diff --git a/tests/read.right b/tests/read.right index e21fcb5f..5f672679 100644 --- a/tests/read.right +++ b/tests/read.right @@ -9,6 +9,8 @@ a. -\ a b\- -\-a b\- -\ a b\- +argv[1] = +argv[1] = argv[1] = <^A> argv[1] = <^A> argv[1] = <^?> diff --git a/tests/read.tests b/tests/read.tests index e5c9bc5a..f05acbf7 100644 --- a/tests/read.tests +++ b/tests/read.tests @@ -26,6 +26,10 @@ echo "\ a b\ " | ( read -r x ; echo -"$x"- ) echo " \ a b\ " | ( read -r x y ; echo -"$x"-"$y"- ) echo " \ a b\ " | ( read -r x ; echo -"$x"- ) +# input ending in backslash +printf 'abc\' | { read var ; recho "$var"; } +printf 'abc\' | { read -r var ; recho "$var"; } + # make sure that CTLESC and CTLNUL are passed through correctly echo $'\001' | ( read var ; recho "$var" ) echo $'\001' | ( read ; recho "$REPLY" ) diff --git a/tests/redir.right b/tests/redir.right index 458befdd..d836f085 100644 --- a/tests/redir.right +++ b/tests/redir.right @@ -118,6 +118,8 @@ c4 is 4 fd 10 fd 8 fd 10 +next fd +fd 10 fd 8 1 2 diff --git a/tests/redir8.sub b/tests/redir8.sub index d2d700cb..314cb1c0 100644 --- a/tests/redir8.sub +++ b/tests/redir8.sub @@ -22,6 +22,11 @@ ${THIS_SH} -c 'exec 8>&1; echo fd 8 >&8' 8>u cat u rm -f u +# command preceding exec acts as if `command' isn't there +${THIS_SH} -c 'command exec 10>&1; echo fd 10 >&10; echo next fd' 10>u +cat u +rm -f u + exec 10>u exec 10>&1; echo 'fd 10' >&10 cat u diff --git a/tests/set-x.right b/tests/set-x.right index 259602e5..230b1df1 100644 --- a/tests/set-x.right +++ b/tests/set-x.right @@ -30,6 +30,9 @@ + foo+=two + echo onetwo onetwo ++ foo=one ++ echo onetwo +onetwo + set +x 1 2 diff --git a/tests/set-x.tests b/tests/set-x.tests index 3723552d..74523bd4 100644 --- a/tests/set-x.tests +++ b/tests/set-x.tests @@ -32,6 +32,8 @@ foo=one foo+=two echo $foo +foo=one echo $foo + set +x # test BASH_XTRACEFD diff --git a/tests/test.right b/tests/test.right index 0927ad08..cb3f94dd 100644 --- a/tests/test.right +++ b/tests/test.right @@ -1,3 +1,5 @@ +t +1 t -a noexist 1 t -a run-all @@ -136,6 +138,8 @@ t 700 -le 1000 -a -n "1" -a "20" = "20" 0 t ! \( 700 -le 1000 -a -n "1" -a "20" = "20" \) 1 +t -n xx -a -z "" -a -t 0 -a -t +0 t /tmp/abc -nt /tmp/def 1 t /tmp/abc -ot /tmp/def @@ -148,6 +152,18 @@ t /tmp/abc -ef /tmp/def 1 t /tmp/abc -ef /tmp/ghi 0 +t noexist -ot /tmp/abc +0 +t /tmp/abc -ot noexist +1 +t noexist -nt /tmp/abc +1 +t noexist -ef /tmp/abc +1 +t -N noexist +1 +t -N /tmp/abc +1 t -r /dev/fd/0 0 t -w /dev/fd/1 @@ -186,6 +202,8 @@ t -v set 0 t -v set 0 +t -R UID +1 t xx -a yy 0 t xx -o "" @@ -216,6 +234,8 @@ t ( -E ) 0 t ( "" ) 1 +t ( -n xx ) +0 t ! -z "$z" 0 t ! -n "$z" @@ -274,7 +294,13 @@ b ( 1 = 2 2 ./test.tests: line 26: test: too many arguments 2 -./test.tests: line 434: [: missing `]' +./test.tests: line 26: test: syntax error: `-t' unexpected +2 +./test.tests: line 26: test: argument expected +2 +./test.tests: line 473: [: missing `]' +2 +./test.tests: line 475: [: missing `]' 2 ./test.tests: line 26: test: (: unary operator expected 2 diff --git a/tests/test.tests b/tests/test.tests index a30ae036..117918d8 100644 --- a/tests/test.tests +++ b/tests/test.tests @@ -27,6 +27,9 @@ t() echo $? } +echo 't' +t + echo 't -a noexist' t -a noexist echo 't -a run-all' @@ -244,6 +247,10 @@ t 700 -le 1000 -a -n "1" -a "20" = "20" echo 't ! \( 700 -le 1000 -a -n "1" -a "20" = "20" \)' t ! \( 700 -le 1000 -a -n "1" -a "20" = "20" \) +# more traditional parsing algorithm +echo 't -n xx -a -z "" -a -t 0 -a -t' +t -n xx -a -z "" -a -t 0 -a -t + touch /tmp/abc sleep 2 touch /tmp/def @@ -265,6 +272,29 @@ t /tmp/abc -ef /tmp/ghi rm /tmp/abc /tmp/def /tmp/ghi +touch /tmp/abc + +echo 't noexist -ot /tmp/abc' +t noexist -ot /tmp/abc + +echo 't /tmp/abc -ot noexist' +t /tmp/abc -ot noexist + +echo 't noexist -nt /tmp/abc' +t noexist -nt /tmp/abc + +echo 't noexist -ef /tmp/abc' +t noexist -ef /tmp/abc + +echo 't -N noexist' +t -N noexist + +# false; it's been read since modified +echo 't -N /tmp/abc' +t -N /tmp/abc + +rm -f /tmp/abc + echo 't -r /dev/fd/0' t -r /dev/fd/0 echo 't -w /dev/fd/1' @@ -317,6 +347,9 @@ set=set echo 't -v set' t -v set +echo 't -R UID' +t -R UID + echo 't xx -a yy' t xx -a yy echo 't xx -o ""' @@ -349,6 +382,8 @@ echo 't ( -E )' t \( -E \) echo 't ( "" )' t \( "" \) +echo 't ( -n xx )' +t \( -n xx \) z=42 @@ -430,9 +465,15 @@ t -A v t 4 -eq 4 -a 2 -ne 5 -a 4 -ne # too many arguments t 4 -eq 4 -a 3 4 +# syntax error +t -n xx -a -z "" -a -t 0 -t +# argument expected +t -n xx -a -z "" -a -t 0 -a [ echo $? +[ -n xx +echo $? t \( \) diff --git a/tests/trap.right b/tests/trap.right index 58d86836..7eab4752 100644 --- a/tests/trap.right +++ b/tests/trap.right @@ -111,10 +111,24 @@ CHLD CHLD CHLD CHLD +BASH_TRAPSIG = USR1 +func=7 +222 +exit=0 +exit=0 +A +In trap-argument: last command preceding the trap action +In a function call: last command in the trap action caught a child death caught a child death caught a child death trap -- 'echo caught a child death' SIGCHLD +echo caught a child death +./trap.tests: line 118: trap: cannot specify both -p and -P +./trap.tests: line 119: trap: -P requires at least one signal name +trap: usage: trap [-Plp] [[action] signal_spec ...] +./trap.tests: line 121: trap: -x: invalid option +trap: usage: trap [-Plp] [[action] signal_spec ...] trap -- 'echo exiting' EXIT trap -- 'echo aborting' SIGABRT trap -- 'echo caught a child death' SIGCHLD diff --git a/tests/trap.tests b/tests/trap.tests index 902de24d..8f4a0955 100644 --- a/tests/trap.tests +++ b/tests/trap.tests @@ -96,6 +96,8 @@ ${THIS_SH} ./trap7.sub # SIGCHLD traps ${THIS_SH} ./trap8.sub +# return without argument in trap string +${THIS_SH} ./trap9.sub # # show that setting a trap on SIGCHLD is not disastrous. @@ -110,6 +112,13 @@ sleep 7 & sleep 6 & sleep 5 & wait trap -p SIGCHLD +trap -P SIGCHLD + +# all errors +trap -p -P +trap -P +trap '' +trap -x # Now reset some of the signals the shell handles specially back to # their default values (with or without the SIG prefix) diff --git a/tests/trap2.sub b/tests/trap2.sub index bd9a76be..f5567db0 100755 --- a/tests/trap2.sub +++ b/tests/trap2.sub @@ -54,6 +54,8 @@ if [ -x /bin/false ]; then FALSE=/bin/false elif [ -x /usr/bin/false ]; then FALSE=/usr/bin/false +elif [ -x /usr/local/bin/false ]; then + FALSE=/usr/local/bin/false else FALSE='command false' fi diff --git a/tests/trap9.sub b/tests/trap9.sub new file mode 100644 index 00000000..484f03be --- /dev/null +++ b/tests/trap9.sub @@ -0,0 +1,84 @@ +# 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 . +# + +# return with argument in trap string while function is executing +trap 'echo BASH_TRAPSIG = $(kill -l $BASH_TRAPSIG); return 7' USR1 +func() { kill -USR1 $$; } +func +echo func=$? + +# test where return with no argument in a trap string gets its exit status +# when a function is executing (posix interp 1602) + +setexit() { return "$1"; } + +# function called in trap string to set $? +# posix interp 1602: the return in the trap string causees the end of +# execution of the trap action +trap 'setexit 222; echo $? ; return' USR1 +process() { kill -USR1 $$; } +process +echo exit=$? +unset -f process + +# posix interp 1602; the return in the trap string interrupts loop and causes +# the end of execution of the trap action +trap 'setexit 123; return' USR1 +loop() { while :; do :; done; } +get_loop_exit() { loop; echo "exit=$?"; } +{ sleep 1; kill -USR1 $$; } & +get_loop_exit +unset -f loop get_loop_exit + +# posix interp 1602; the return in `check' does not cause the end of execution +# of the trap action +check() { false; return; } +handle() { check && echo B || echo A; } +trap handle USR1 +kill -USR1 $$ +unset -f check handle + +# posix interp 1602: show where we get the value of $? for trap actions +# return in trap string causes end of execution of trap action +invoke() { kill -USR1 $$; return 222; } +trap 'setexit 111; return' USR1 +invoke +case $? in +(0) echo 'In trap-argument: last command preceding the trap action' ;; +(111) echo 'In trap-argument: last command in the trap action' ;; +(222) echo 'In trap-argument: (failed to exit the function)' ;; +(*) echo 'In trap-argument: (unexpected)' ;; +esac + +# return in `handler' does not cause the end of execution of the trap action +stat=99 +handler() { setexit 111; return; } +trap 'handler; stat=$?; return' USR1 +invoke +case $stat in +(0) echo 'In a function call: last command preceding the trap action' ;; +(111) echo 'In a function call: last command in the trap action' ;; +(*) echo 'In a function call: (unexpected)' ;; +esac +unset -f invoke handler +unset -f setexit + +# posix interp 1602: return in function does not cause end of trap action +ReturnFalse() +{ + false ; return +} + +trap 'ReturnFalse && echo "woops"' EXIT +(exit 0) # set exit status diff --git a/tests/type.right b/tests/type.right index 6cfa14ed..a3fd4b9b 100644 --- a/tests/type.right +++ b/tests/type.right @@ -1,6 +1,7 @@ ./type.tests: line 22: type: -r: invalid option type: usage: type [-afptP] name [name ...] ./type.tests: line 25: type: notthere: not found +./type.tests: line 29: command: notthere: not found function keyword builtin @@ -24,7 +25,7 @@ func () } while while is a shell keyword -./type.tests: line 56: type: m: not found +./type.tests: line 59: type: m: not found alias m='more' alias m='more' m is aliased to `more' @@ -37,8 +38,8 @@ builtin builtin is a shell builtin /bin/sh /bin/sh is /bin/sh -./type.tests: line 78: type: func: not found -./type.tests: line 80: type: m: not found +./type.tests: line 81: type: func: not found +./type.tests: line 83: type: m: not found /bin/sh /tmp/bash bash is hashed (/tmp/bash) @@ -133,3 +134,8 @@ EOF ); echo "coprocs created" } +cat is /bin/cat +cat is aliased to `echo cat' +/bin/cat +break is a shell builtin +break is a special shell builtin diff --git a/tests/type.tests b/tests/type.tests index fd39c18a..13e6cc46 100644 --- a/tests/type.tests +++ b/tests/type.tests @@ -21,10 +21,13 @@ type # this should be a usage error type -r ${THIS_SH} -# these should behave identically +# these should behave identically, but POSIX says command -v is silent if the name is not found type notthere command -v notthere +# but this will produce an error message +command -V notthere + alias m=more unset -f func 2>/dev/null @@ -102,9 +105,7 @@ f() { type f | cat -v ${THIS_SH} type1.sub - ${THIS_SH} type2.sub - ${THIS_SH} type3.sub - ${THIS_SH} type4.sub +${THIS_SH} type5.sub diff --git a/tests/type5.sub b/tests/type5.sub new file mode 100644 index 00000000..1bd879e0 --- /dev/null +++ b/tests/type5.sub @@ -0,0 +1,41 @@ +# 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 . +# + +# make sure . is not in $PATH +PATH=/bin:/usr/bin:/usr/local/bin + +# test type -P + +# executable in current directory +TDIR=$TMPDIR/type-$$ +[ -d "$TDIR" ] || mkdir "$TDIR" +cd -P "$TDIR" || exit 1 + +touch e ; chmod +x e; type -P e; rm -f e + +shopt -s expand_aliases + +type cat +alias cat='echo cat' +type -f cat +type -P cat + +# some random tests + +# the difference between posix and default modes +type break +set -o posix; type break; set +o posix + +cd "$OLDPWD" +rm -rf "$TDIR" diff --git a/tests/varenv7.sub b/tests/varenv7.sub index 4b259606..078d2db8 100644 --- a/tests/varenv7.sub +++ b/tests/varenv7.sub @@ -17,7 +17,7 @@ foo() local -r myvar=0 echo "${myvar[@]}" - declare -p myvar + local -p myvar } foo2() @@ -26,7 +26,7 @@ foo2() local -r myvar=1 echo "${myvar}" - declare -p myvar + local -p myvar } declare -a outside=()