mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
test/[: Fix binary -a/-o operators in POSIX mode
POSIX requires test "$a" -a "$b" to return true if both $a and $b are non-empty, and test "$a" -o "$b" to return true if either $a or $b is non-empty. In ksh, this fails if "$a" is '!' or '(' as this causes ksh to interpret the -a and -o as unary operators (-a being a file existence test like -e, and -o being a shell option test). $ test ! -a ""; echo "$?" 0 (expected: 1/false) $ set -o trackall; test ! -o trackall; echo "$?" 1 (expected: 0/true) $ test \( -a \); echo "$?" ksh: test: argument expected 2 (expected: 0/true) $ test \( -o \) ksh: test: argument expected 2 (expected: 0/true) Unfortunately this problem cannot be fixed without risking breakage in legacy scripts. For instance, a script may well use test ! -a filename to check that a filename is nonexistent. POSIX specifies that this always return true as it is a test for the non-emptiness of both strings '!' and 'filename'. So this commit fixes it for POSIX mode only. src/cmd/ksh93/bltins/test.c: e3(): - If the posix option is active, specially handle the case of having at least three arguments with the second being -a or -o, overriding their handling as unary operators. src/cmd/ksh93/data/testops.c: - Update 'test --man --' date and say that unary -a is deprecated. src/cmd/ksh93/sh.1: - Document the fix under the -o posix option. - For test/[, explain that binary -a/-o are deprecated. src/cmd/ksh93/tests/bracket.sh: - Add tests based on reproducers in bug report. Resolves: https://github.com/ksh93/ksh/issues/330
This commit is contained in:
parent
568cfdbda7
commit
6f5c9fea93
6 changed files with 47 additions and 8 deletions
8
NEWS
8
NEWS
|
@ -3,6 +3,14 @@ For full details, see the git log at: https://github.com/ksh93/ksh
|
||||||
|
|
||||||
Any uppercase BUG_* names are modernish shell bug IDs.
|
Any uppercase BUG_* names are modernish shell bug IDs.
|
||||||
|
|
||||||
|
2021-11-13:
|
||||||
|
|
||||||
|
- The test/[ built-in command is fixed so that the binary -a (and) and -o (or)
|
||||||
|
operators, as in [ "$a" -a "$b" ] or [ "$a" -o "$b" ], work even if "$a" is
|
||||||
|
'!' or '('. To avoid breaking backwards compatibility with the nonstandard
|
||||||
|
unary [ -a "$file" ] and [ -o "$option" ] operators in combination with '!'
|
||||||
|
or parentheses, this fix is only activated if the posix option is on.
|
||||||
|
|
||||||
2021-11-07:
|
2021-11-07:
|
||||||
|
|
||||||
- Fixed a bug that could corrupt output if standard output is closed upon
|
- Fixed a bug that could corrupt output if standard output is closed upon
|
||||||
|
|
|
@ -243,8 +243,9 @@ done:
|
||||||
/*
|
/*
|
||||||
* evaluate a test expression.
|
* evaluate a test expression.
|
||||||
* flag is 0 on outer level
|
* flag is 0 on outer level
|
||||||
* flag is 1 when in parenthesis
|
* flag is 1 when in parentheses
|
||||||
* flag is 2 when evaluating -a
|
* flag is 2 when evaluating -a (TEST_AND)
|
||||||
|
* flag is 3 when evaluating -o (TEST_OR)
|
||||||
*/
|
*/
|
||||||
static int expr(struct test *tp,register int flag)
|
static int expr(struct test *tp,register int flag)
|
||||||
{
|
{
|
||||||
|
@ -308,6 +309,17 @@ static int e3(struct test *tp)
|
||||||
register int op;
|
register int op;
|
||||||
char *binop;
|
char *binop;
|
||||||
arg=nxtarg(tp,0);
|
arg=nxtarg(tp,0);
|
||||||
|
if(sh_isoption(SH_POSIX) && tp->ap + 1 < tp->ac && ((op=sh_lookup(tp->av[tp->ap],shtab_testops)) & TEST_BINOP))
|
||||||
|
{ /*
|
||||||
|
* In POSIX mode, makes sure standard binary -a/-o takes precedence
|
||||||
|
* over nonstandard unary -a/-o if the lefthand expression is "!" or "("
|
||||||
|
*/
|
||||||
|
tp->ap++;
|
||||||
|
if(op==TEST_AND)
|
||||||
|
return(*arg && expr(tp,2));
|
||||||
|
else /* TEST_OR */
|
||||||
|
return(*arg || expr(tp,3));
|
||||||
|
}
|
||||||
if(arg && c_eq(arg, '!'))
|
if(arg && c_eq(arg, '!'))
|
||||||
return(!e3(tp));
|
return(!e3(tp));
|
||||||
if(c_eq(arg, '('))
|
if(c_eq(arg, '('))
|
||||||
|
|
|
@ -57,7 +57,7 @@ const Shtable_t shtab_testops[] =
|
||||||
};
|
};
|
||||||
|
|
||||||
const char sh_opttest[] =
|
const char sh_opttest[] =
|
||||||
"[-1c?\n@(#)$Id: test (ksh 93u+m) 2020-08-31 $\n]"
|
"[-1c?\n@(#)$Id: test (ksh 93u+m) 2021-11-13 $\n]"
|
||||||
"[--catalog?" SH_DICT "]"
|
"[--catalog?" SH_DICT "]"
|
||||||
"[+NAME?test, [ - evaluate expression]"
|
"[+NAME?test, [ - evaluate expression]"
|
||||||
"[+DESCRIPTION?\btest\b evaluates expressions and returns its result using the "
|
"[+DESCRIPTION?\btest\b evaluates expressions and returns its result using the "
|
||||||
|
@ -97,7 +97,7 @@ const char sh_opttest[] =
|
||||||
"[+?Operators marked with a * are not part of the POSIX standard.]"
|
"[+?Operators marked with a * are not part of the POSIX standard.]"
|
||||||
"}"
|
"}"
|
||||||
"[+UNARY OPERATORS?These evaluate as True if:]{"
|
"[+UNARY OPERATORS?These evaluate as True if:]{"
|
||||||
"[+-a \afile\a *?Same as \b-e\b.]"
|
"[+-a \afile\a *?Deprecated. Same as \b-e\b.]"
|
||||||
"[+-b \afile\a?\afile\a is a block special file.]"
|
"[+-b \afile\a?\afile\a is a block special file.]"
|
||||||
"[+-c \afile\a?\afile\a is a character special file.]"
|
"[+-c \afile\a?\afile\a is a character special file.]"
|
||||||
"[+-d \afile\a?\afile\a is a directory.]"
|
"[+-d \afile\a?\afile\a is a directory.]"
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
#define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */
|
#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_SVER "1.0.0-beta.2" /* semantic version number: https://semver.org */
|
||||||
#define SH_RELEASE_DATE "2021-11-07" /* must be in this format for $((.sh.version)) */
|
#define SH_RELEASE_DATE "2021-11-13" /* must be in this format for $((.sh.version)) */
|
||||||
#define SH_RELEASE_CPYR "(c) 2020-2021 Contributors to ksh " SH_RELEASE_FORK
|
#define SH_RELEASE_CPYR "(c) 2020-2021 Contributors to ksh " SH_RELEASE_FORK
|
||||||
|
|
||||||
/* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */
|
/* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */
|
||||||
|
|
|
@ -7244,6 +7244,12 @@ disables the \fB&>\fR redirection shorthand;
|
||||||
.IP \[bu]
|
.IP \[bu]
|
||||||
makes the \fB<>\fR redirection operator default to redirecting standard input
|
makes the \fB<>\fR redirection operator default to redirecting standard input
|
||||||
if no file descriptor number precedes it;
|
if no file descriptor number precedes it;
|
||||||
|
.IP \[bu]
|
||||||
|
changes the \fBtest\fR/\fB[\fR built-in command to make its deprecated
|
||||||
|
\fIexpr1\fR \fB-a\fR \fIexpr2\fR and \fIexpr1\fR \fB-o\fR \fIexpr2\fR operators
|
||||||
|
work even if \fIexpr1\fR equals "\fB!\fR" or "\fb(\fR" (which means the
|
||||||
|
nonstandard unary \fB-a\fR \fIfile\fR and \fB-o\fR \fIoption\fR operators
|
||||||
|
cannot be directly negated using \fB!\fR or wrapped in parentheses);
|
||||||
and
|
and
|
||||||
.IP \[bu]
|
.IP \[bu]
|
||||||
disables a hack that makes \fBtest -t\fR (\fB[ -t ]\fR) equivalent to
|
disables a hack that makes \fBtest -t\fR (\fB[ -t ]\fR) equivalent to
|
||||||
|
@ -7451,13 +7457,15 @@ to those specified for the \f3[[\fP compound command under
|
||||||
above, but with several important differences. The \f3=\fP, \f3==\fP and
|
above, but with several important differences. The \f3=\fP, \f3==\fP and
|
||||||
\f3!=\fP operators test for string (in)equality without pattern matching;
|
\f3!=\fP operators test for string (in)equality without pattern matching;
|
||||||
the \f3==\fP variant is nonstandard and should not be used. The \f3=\(ap\fP,
|
the \f3==\fP variant is nonstandard and should not be used. The \f3=\(ap\fP,
|
||||||
\f3<\fP, \f3>\fP, \f3&&\fP and \f3||\fP operators are not available. Most
|
\f3<\fP, \f3>\fP, \f3&&\fP and \f3||\fP operators are not available. Instead
|
||||||
|
of \f3&&\fP and \f3||\fP, the \f3-a\fP and \f3-o\fP binary operators can be
|
||||||
|
used, but they are fraught with pitfalls due to grammatical ambiguities and
|
||||||
|
therefore deprecated in favor of invoking separate \f3test\fP commands. Most
|
||||||
importantly, as \f3test\fP and \f3[\fP are simple regular commands, field
|
importantly, as \f3test\fP and \f3[\fP are simple regular commands, field
|
||||||
splitting and file name generation \f2are\fP performed on all their
|
splitting and file name generation \f2are\fP performed on all their
|
||||||
arguments and all aspects of regular shell grammar (such as redirection)
|
arguments and all aspects of regular shell grammar (such as redirection)
|
||||||
remain active. This is usually harmful, so care must be taken to quote
|
remain active. This is usually harmful, so care must be taken to quote
|
||||||
arguments and expansions to avoid this. There are also certain inherent
|
arguments and expansions to avoid this. To avoid the many pitfalls
|
||||||
grammatical ambiguities in the expressions. To avoid the many pitfalls
|
|
||||||
arising from these issues, the \f3[[\fP compound command should be used
|
arising from these issues, the \f3[[\fP compound command should be used
|
||||||
instead. The primary purpose of the \f3test\fP and \f3[\fP commands is
|
instead. The primary purpose of the \f3test\fP and \f3[\fP commands is
|
||||||
compatibility with other shells that lack \f3[[\fP.
|
compatibility with other shells that lack \f3[[\fP.
|
||||||
|
|
|
@ -423,5 +423,16 @@ foo=10
|
||||||
&& [ ! ! -n x -a ! ! ! ! -n x -a ! ! ! ! ! ! -n x ] \
|
&& [ ! ! -n x -a ! ! ! ! -n x -a ! ! ! ! ! ! -n x ] \
|
||||||
|| err_exit '! does not negate ! in [ ... ]'
|
|| err_exit '! does not negate ! in [ ... ]'
|
||||||
|
|
||||||
|
# ======
|
||||||
|
# https://github.com/ksh93/ksh/issues/330
|
||||||
|
if (set -o posix) 2>/dev/null
|
||||||
|
then set -o posix -o trackall
|
||||||
|
test ! -a "" && err_exit "POSIX test/[: binary -a operator does not work with '!' as left-hand expression"
|
||||||
|
test \( -a \) 2>/dev/null || err_exit "POSIX test/[: binary -a operator does not work with '(' as left-hand expression"
|
||||||
|
test ! -o trackall || err_exit "POSIX test/[: binary -o operator does not work with '!' as left-hand expression"
|
||||||
|
test \( -o \) 2>/dev/null || err_exit "POSIX test/[: binary -o operator does not work with '(' as left-hand expression"
|
||||||
|
set +o posix
|
||||||
|
fi
|
||||||
|
|
||||||
# ======
|
# ======
|
||||||
exit $((Errors<125?Errors:125))
|
exit $((Errors<125?Errors:125))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue