diff --git a/NEWS b/NEWS index 2b9911b03..b2484cede 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,9 @@ Any uppercase BUG_* names are modernish shell bug IDs. nonexistent positional parameter such as $1, $2, ... is accessed, as other shells do and POSIX requires. (This does *not* apply to "$@" and "$*".) +- If 'set -u'/'set -o nounset' is active, then the shell now errors out if $! + is accessed before the shell has launched any background process. + 2020-06-06: - The 'times' command is now a builtin command that conforms to POSIX diff --git a/src/cmd/ksh93/sh/macro.c b/src/cmd/ksh93/sh/macro.c index d789d1941..2899908ba 100644 --- a/src/cmd/ksh93/sh/macro.c +++ b/src/cmd/ksh93/sh/macro.c @@ -2790,6 +2790,19 @@ static char *special(Shell_t *shp,register int c) else return(shp->st.cmdname); } + /* Handle 'set -u'/'set -o nounset' for special parameters */ + if(sh_isoption(SH_NOUNSET)) + { + int d=fcget(); + fcseek(-1); + if(!(d && strchr(":+-?=",d))) + { + char c_str[2]; + c_str[0]=(char)c; + c_str[1]='\0'; + errormsg(SH_DICT,ERROR_exit(1),e_notset,c_str); + } + } return(NIL(char*)); } diff --git a/src/cmd/ksh93/tests/options.sh b/src/cmd/ksh93/tests/options.sh index 1375440e4..a8abb2d86 100755 --- a/src/cmd/ksh93/tests/options.sh +++ b/src/cmd/ksh93/tests/options.sh @@ -511,10 +511,19 @@ $SHELL -uc 'var=foo;unset var;: ${var%foo}' >/dev/null 2>&1 && err_exit '${var%f $SHELL -uc 'var=foo;unset var;: ${!var}' >/dev/null 2>&1 && err_exit '${!var} should fail with set -u' $SHELL -uc 'var=foo;unset var;: ${#var}' >/dev/null 2>&1 && err_exit '${#var} should fail with set -u' $SHELL -uc 'var=foo;unset var;: ${var-OK}' >/dev/null 2>&1 || err_exit '${var-OK} should not fail with set -u' -$SHELL -uc 'var=foo;nset var;: ${var:-OK}' >/dev/null 2>&1 || err_exit '${var:-OK} should not fail with set -u' +$SHELL -uc 'var=foo;unset var;: ${var:-OK}' >/dev/null 2>&1 || err_exit '${var:-OK} should not fail with set -u' (set -u -- one two; : $2) 2>/dev/null || err_exit "an unset PP failed with set -u" (set -u -- one two; : $3) 2>/dev/null && err_exit "a set PP failed to fail with set -u" +(set -u -- one two; : ${3%foo}) 2>/dev/null && err_exit '${3%foo} failed to fail with set -u' +(set -u -- one two; : ${3-OK}) 2>/dev/null || err_exit '${3-OK} wrongly failed with set -u' +(set -u -- one two; : ${3:-OK}) 2>/dev/null || err_exit '${3:-OK} wrongly failed with set -u' +(set -u -- one two; : ${#3}) 2>/dev/null && err_exit '${#3} failed to fail with set -u' (set -u --; : $@ $*) 2>/dev/null || err_exit '$@ and/or $* fail to be exempt from set -u' +$SHELL -uc ': $!' 2>/dev/null && err_exit '$! failed to fail with set -u' +$SHELL -uc ': ${!%foo}' >/dev/null 2>&1 && err_exit '${!%foo} should fail with set -u' +$SHELL -uc ': ${#!}' >/dev/null 2>&1 && err_exit '${#!} should fail with set -u' +$SHELL -uc ': ${!-OK}' >/dev/null 2>&1 || err_exit '${!-OK} should not fail with set -u' +$SHELL -uc ': ${!:-OK}' >/dev/null 2>&1 || err_exit '${!:-OK} should not fail with set -u' z=$($SHELL 2>&1 -uc 'print ${X23456789012345}') [[ $z == *X23456789012345:* ]] || err_exit "error message garbled with set -u got $z"