Discussion:
Strange (wrong?) behaviour of "test ! -a file"
Martin Schulte
2018-10-21 09:32:11 UTC
Permalink
Hello,

"help test" states that "-a file" and "-e file" do them same ("True if
file exists.")

This is not true when negating the result as you can see from the output
below. The bash builtin even behaves different than the test from
coreutils.

It looks as if "! -a file" results in "( ! ) -a ( file )" in bash while
it results in "! ( -a file )" in coreutils' test.

Given all the problems with "-a" as the AND and the fact that POSIX
doesn't have a "-a" filetest I suggest to mark "-a file" as strongly
deprecated in the help page or remove it at all from test rather than
thinking about if this is a bug and how to fix it.

There's a related discussion in the coreutils mailing list:

http://lists.gnu.org/archive/html/bug-coreutils/2018-10/msg00117.html

Regards,

Martin

***@hidden:~/langs/sh$ cat minus-a
#!/bin/bash

set -o nounset

file=/etc/passwd

echo $BASH_VERSION
/usr/bin/[ --version | head -1

for cmd in test /usr/bin/test
do
for op in -a -e
do
printf "%-30s -> " "$cmd ! $op $file" ; $cmd ! $op $file ; echo $?
done
done | cat -n
***@hidden:~/langs/sh$ ./minus-a
4.4.12(1)-release
[ (GNU coreutils) 8.26
1 test ! -a /etc/passwd -> 0
2 test ! -e /etc/passwd -> 1
3 /usr/bin/test ! -a /etc/passwd -> 1
4 /usr/bin/test ! -e /etc/passwd -> 1
Chet Ramey
2018-10-21 17:03:06 UTC
Permalink
Post by Martin Schulte
Hello,
"help test" states that "-a file" and "-e file" do them same ("True if
file exists.")
This is not true when negating the result as you can see from the output
below. The bash builtin even behaves different than the test from
coreutils.
This is documented behavior consistent with the POSIX standard. It's been
this way for so long, there is even a question in the long-dormant FAQ
about it (E1).

The `test' command's behavior is determined by the number of arguments,
as specified by POSIX:

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html#tag_20_128

The help text for test says

"The behavior of test depends on the number of arguments. Read the
bash manual page for the complete specification."

The man page says:

3 arguments
The following conditions are applied in the order listed.
If the second argument is one of the binary conditional
operators listed above under CONDITIONAL EXPRESSIONS, the
result of the expression is the result of the binary test
using the first and third arguments as operands. The -a
and -o operators are considered binary operators when
there are three arguments.

This is the order in which the POSIX algorithm specifies the conditions.
Post by Martin Schulte
It looks as if "! -a file" results in "( ! ) -a ( file )" in bash while
it results in "! ( -a file )" in coreutils' test.
Coreutils does the tests in a different order than they appear in the POSIX
standard.
--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU ***@case.edu http://tiswww.cwru.edu/~chet/
Ilkka Virta
2018-10-21 18:24:24 UTC
Permalink
Post by Chet Ramey
The help text for test says
"The behavior of test depends on the number of arguments. Read the
bash manual page for the complete specification."
Can I suggest adding that note from the help text to the manual under
"Bash Conditional Expressions" too? Perhaps also explicitly noting the
clash with the binary operators in the descriptions of -a and -o, too.

Something along the lines of the attached patch.

I also think the description of the 3-argument test would be clearer
with numbering, so I added that too.
--
Ilkka Virta / ***@iki.fi
Loading...