help-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: how much are "historic" issues with test / [ still an issue


From: Christoph Anton Mitterer
Subject: Re: how much are "historic" issues with test / [ still an issue
Date: Tue, 25 May 2021 18:16:20 +0200
User-agent: Evolution 3.38.3-1

Hey.


On Tue, 2021-05-25 at 11:04 -0400, Chet Ramey wrote:
> The bash `test' implements the POSIX algorithm, which was first
> published
> in the 1003.2 drafts, so bash has provided a way to avoid those
> problems
> for at least 30 years.

And AFAIU that's basically the determination based on the number of
arguments given to test (i.e. without the ] in the [] case), as
described in the operands section of:
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html


That still has a number of "Otherwise, produce unspecified results.":

I guess for the 2-arguments case, that would be if one writes some
obvious error like
test foo bar
or
test $var1 $var2
with $var1 not being ! or any of the unary operators.


And the same for 3-arguments case, if one does e.g.:
test $var1 "" $var2
test $var1 -xx $var2
or similar stuff.

I would have understood:
> 3 arguments:
>     If $2 is a binary primary, perform the binary test of $1 and $3.
>     If $1 is '!', negate the two-argument test of $2 and $3.
as:
First, check whether $2 is any of the binary operators.
Second, if $1 is !, negate the result of the 2-argument test from $2
and $3.

And that's also the reason why test ! = "" works, because it's not the
negation of a = "" but the comparison of two strings.


>  If you don't quote the arguments, you
> never know what `test' is going to see in the first place.
Sure that's clear.


> >But the result seems to be the same as with && ... and even if
> >one takes bash with has the unary -a FILE ... it doesn't seem to do
> >a: ! ( -a FILE )
> 
> That case is covered by operator precedence parsing. The parens have
> a 
> higher precedence than binary operators, so this returns a 0 status
> if
> FILE doesn't exist. It's a convoluted way to write it, but it is
> different
> from `! -a FILE' because the -a binary operator has a higher
> precedence
> than `!' when three arguments are supplied.

So what if I have >= 4 arguments... e.g.
$var1 = $var2 -a $var3 -z $var4

I guess that is then indeed a problem even in modern shells?
Cause it could end up being that:
! = = -a -o -z ""


Does it help if one always uses parentheses so that no more than 3
arguments are in one pair of parentheses?
Like:
\( $var1 = $var2 \) -a \( $var3 -z $var4 \)

The algorithm doesn't really say much about these, so I'd guess at
least per the standard these are prone to be ambiguous?



> > Even more importantly for me, cases like:
> >     > test "$response" = "expected string"
> >     shall be written as:
> >     > test "X$response" = "Xexpected string"
> > 
> > I guess the leading X is simply to "escape" any possible meta-
> > character
> > like ( ! or -, right ?
> 
> Historically, yes.

So at least in 3 argument case this is safe, and including "X" or
similar not necessary.
But I guess in the 


> That falls into `historical algorithm' territory, since there are
> five
> arguments.
> 
> You can rewrite as
> 
>         test -d "$1" || test -d "$2"
> or
>         [[ -d "$1" || -d "$2" ]]
> 
> and have the advantage of short-circuiting after the first test if it
> ends
> up being true.

test's -a and -o don't short circuit?



So long story short:
- as long as one uses <= 3 arguments, things always works as expected,
  even if $1 and $3 are variables with arbitrary values set by the user

- 4 arguments still works if the first is !   or   if $1 and $4 are (
  and )

- anything else >= 4 might is ambiguous, and one should use the forms
with multiple test(s) and combine those via ||, &&, and the shell's ( )
(i.e. the unquoted parentheses that cause subshell evaluation).


Right?


Thanks,
Chris.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]