#421591 bash: test builtin (or [) does not behave correctly

Package:
bash
Source:
bash
Description:
GNU Bourne Again SHell
Submitter:
Vincent Lefevre
Date:
2024-03-21 10:39:02 UTC
Severity:
normal
Tags:
#421591#5
Date:
2007-04-30 11:49:38 UTC
From:
To:
The bash man page says that the unary -a behaves like -e:

       -a file
              True if file exists.
       -e file
              True if file exists.

But I get:

vlefevre@vin:~$ touch exists
vlefevre@vin:~$ [ ! -e exists ] || echo found
found
vlefevre@vin:~$ [ ! -a exists ] || echo found
vlefevre@vin:~$

However the following forms work as expected:

vlefevre@vin:~$ [[ ! -e exists ]] || echo found
found
vlefevre@vin:~$ [[ ! -a exists ]] || echo found
found
vlefevre@vin:~$ [ -e exists ] && echo found
found
vlefevre@vin:~$ [ -a exists ] && echo found
found
vlefevre@vin:~$

Note: I don't think it is a good idea to use the non-standard unary -a
with [, but this is a bug anyway.

#421591#10
Date:
2007-04-30 13:44:34 UTC
From:
To:
In fact, this seems to be the intended behavior, but the man page
is not well structured. It first says:

              ! expr True if expr is false.

but then, says something about the number of araguments. This part
should appear first. Moreover, the case "! -a file" is not handled
in the description:

    3 arguments
        If the second argument is one of the  binary  conditional
        operators listed above under CONDITIONAL EXPRESSIONS, the

As the first argument is !, the -a is a unary conditional operator
as described above, so we are not in this case.

        result of the expression is the result of the binary test
        using  the first and third arguments as operands.  If the
        first argument is !, the value is  the  negation  of  the
        two-argument  test  using the second and third arguments.
[...]

We are in this case.

        If the first argument is exactly ( and the third argument
        is  exactly ), the result is the one-argument test of the
        second argument.  Otherwise,  the  expression  is  false.
        The  -a  and -o operators are considered binary operators
        in this case.

But now, "in this case" is ambiguous. The man page should probably
have been said "when there are 3 arguments". And it should have been
said first. And above, instead of saying "If the second argument is
one of the binary conditional operators listed above under CONDITIONAL
EXPRESSIONS" (which is ambiguous, as seen), the man page should have
said "If the second argument is -a or -o".

#421591#15
Date:
2007-08-22 13:29:55 UTC
From:
To:
Also, the case with 5 or more arguments is not clear either.
In fact, I don't know if this is a bug (due to a primitive parser)
or a bad documentation.

vlefevre@vin:~$ [ true -a \( ! -a \) ] && echo OK
bash: [: `)' expected, found ]

It is not clear whether the second -a is
  1. -a <file> where <file> is ')';
  2. -a <file> where <file> is a missing parameter[*], ')' being
     part of the ( expr ) form;
  3. the string '-a' (assuming there are no parameters left, see
     point 2).

[*] The man page says:

    See the description of the test builtin command (section SHELL
    BUILTIN COMMANDS below) for the handling of parameters (i.e.
    missing parameters).

But nothing is described in the test builtin concerning missing
parameters.

The parser seems to follow point 1. But a grammar-based parser would
follow point 2 or 3.

#421591#20
Date:
2007-08-22 14:05:20 UTC
From:
To:
which case is specified by POSIX:

vlefevre@vin:~$ [ \( ! -e \) ] && echo OK
bash: [: `)' expected, found ]

POSIX says: "However, when using the "[...]" form, the right-bracket
final argument shall not be counted in this algorithm."

So, we are in the 4-argument case: ( ! -e )

POSIX says in this case: "If $1 is '(' and $4 is ')', perform the
two-argument test of $2 and $3."

i.e. this is equivalent to: test ! -e

POSIX says in this 2-argument case: "If $1 is '!', exit true if $2 is
null, false if $2 is not null."

So, that's perfectly valid, and the error returned by bash is a bug.

#421591#25
Date:
2008-02-11 12:20:25 UTC
From:
To:
retitle 421591 bash: test builtin (or [) does not behave correctly
thanks

As a summary, the following test at least does not behave correctly:

vlefevre@vin:~$ test \( ! -e \) ; echo $?
bash: test: `)' expected
2

And I think this one is also buggy:

vlefevre@vin:~$ test true -a \( ! -a \) ; echo $?
bash: test: `)' expected
2

FYI, the coreutils and zsh test utility both output 1 on these tests;
so does dash on the second one only.

I recall the POSIX spec:

http://www.opengroup.org/onlinepubs/009695399/utilities/test.html

#421591#32
Date:
2024-03-21 01:38:10 UTC
From:
To:
found 421591 5.2.21-2
thanks

In bash 5.2.21-2 the first invocation behaves correctly:

     $ test \( ! -e \) ; echo $?
     1

but the second is still broken:

     test true -a \( ! -a \) ; echo $?
     -bash: test: `)' expected
     2

#421591#41
Date:
2024-03-21 10:35:22 UTC
From:
To:
dash now gives 1 on both cases, as expected. But for the second one,
zsh now gives an error and 2 like bash; I would see this as a bug,
like for bash.

Note that

  $ test \( ! -a \) ; echo $?
  1

for both bash and zsh, so "test true -a \( ! -a \)" should really
behave in the same way.