diff --git a/NEWS b/NEWS index a82d7e879206..a3222b4d96fa 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,12 @@ For full details, see the git log at: https://github.com/ksh93/ksh/tree/1.0 Any uppercase BUG_* names are modernish shell bug IDs. +2022-07-05: + +- Fixed a spurious syntax error on encountering a process substitution + following a redirection without being an argument to a redirection. + For example, this now writes 'OK' to standard error: cat >&2 <(echo OK) + 2022-07-02: - Fixed a bug where, if the last command in a subshell was an external diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index 06a605bc3c50..9a7b923f5a7d 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -23,7 +23,7 @@ #define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */ #define SH_RELEASE_SVER "1.0.0-beta.2" /* semantic version number: https://semver.org */ -#define SH_RELEASE_DATE "2022-07-02" /* must be in this format for $((.sh.version)) */ +#define SH_RELEASE_DATE "2022-07-05" /* must be in this format for $((.sh.version)) */ #define SH_RELEASE_CPYR "(c) 2020-2022 Contributors to ksh " SH_RELEASE_FORK /* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */ diff --git a/src/cmd/ksh93/sh/parse.c b/src/cmd/ksh93/sh/parse.c index 9d290ef4f7bf..17a714218e76 100644 --- a/src/cmd/ksh93/sh/parse.c +++ b/src/cmd/ksh93/sh/parse.c @@ -48,6 +48,7 @@ static Shnode_t *makeparent(Lex_t*, int, Shnode_t*); static Shnode_t *makelist(Lex_t*, int, Shnode_t*, Shnode_t*); static struct argnod *qscan(struct comnod*, int); static struct ionod *inout(Lex_t*,struct ionod*, int); +static char inout_found_procsub; static Shnode_t *sh_cmd(Lex_t*,int,int); static Shnode_t *term(Lex_t*,int); static Shnode_t *list(Lex_t*,int); @@ -1583,6 +1584,7 @@ static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io) lexp->token = tok = 0; if((tok==IPROCSYM || tok==OPROCSYM)) { + procsub: argp = process_sub(lexp,tok); argno = -1; *argtail = argp; @@ -1655,6 +1657,8 @@ static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io) } else t->comio = io = inout(lexp,(struct ionod*)0,0); + if(inout_found_procsub) + goto procsub; } } *argtail = 0; @@ -1753,6 +1757,9 @@ static struct ionod *inout(Lex_t *lexp,struct ionod *lastio,int flag) Stk_t *stkp = sh.stk; char *iovname=0; register int errout=0; + /* return if a process substitution is found without a redirection */ + if(inout_found_procsub = (token==IPROCSYM || token==OPROCSYM)) + return(lastio); if(token==IOVNAME) { iovname=lexp->arg->argval+1; diff --git a/src/cmd/ksh93/tests/io.sh b/src/cmd/ksh93/tests/io.sh index 0fb31811d876..4e640d957861 100755 --- a/src/cmd/ksh93/tests/io.sh +++ b/src/cmd/ksh93/tests/io.sh @@ -974,5 +974,35 @@ then "(expected $(printf %q "$exp"), got $(printf %q "$got"))" fi +# ====== +# A process substitution should be valid after a redirection +# https://github.com/ksh93/ksh/issues/418 +got=$(set +x; eval ': &1) +[[ e=$? -eq 0 && -z $got ]] || err_exit "spurious syntax error on process substitution following redirection" \ + "(expected status 0 and '', got status $e and $(printf %q "$got"))" +got=$(set +x; eval ': <&1 <(/dev/null' 2>&1) +exp='*: syntax error at line *: `end of file'\'' unexpected' +[[ $got == $exp ]] || err_exit "': <&1 <(/dev/null' fails to throw a syntax error" \ + "(expected match of $(printf %q "$exp"), got $(printf %q "$got"))" +got=$(set +x; eval '{ :; } <(: wrong)' 2>&1) +exp='*: syntax error at line *: `<('\'' unexpected' +[[ $got == $exp ]] || err_exit "'{ :; } <(: wrong)' throws incorrect syntax error" \ + "(expected match of $(printf %q "$exp"), got $(printf %q "$got"))" +got=$(set +x; eval ': >/dev/null >(true)' 2>&1) +[[ e=$? -eq 0 && -z $got ]] || err_exit "spurious syntax error on process substitution following redirection" \ + "(expected status 0 and '', got status $e and $(printf %q "$got"))" +got=$(set +x; eval ': >&1 >(/dev/null' 2>&1) +exp='*: syntax error at line *: `end of file'\'' unexpected' +[[ $got == $exp ]] || err_exit "': >&1 >(/dev/null' fails to throw a syntax error" \ + "(expected match of $(printf %q "$exp"), got $(printf %q "$got"))" +got=$(set +x; eval '{ :; } >(: wrong)' 2>&1) +exp='*: syntax error at line *: `>('\'' unexpected' +[[ $got == $exp ]] || err_exit "'{ :; } >(: wrong)' throws incorrect syntax error" \ + "(expected match of $(printf %q "$exp"), got $(printf %q "$got"))" +got=$(set +x; eval 'cat >out <(echo OK)' 2>&1; echo ===; cat out) +exp=$'===\nOK' +[[ $got == "$exp" ]] || err_exit "process substitution nixes output redirection" \ + "(expected $(printf %q "$exp"), got $(printf %q "$got"))" + # ====== exit $((Errors<125?Errors:125))