In bash
, with context of two arguments test
command, -a file
and -e file
are the same. But they have some difference, because -a
is also a binary operator.
-e
unary is defined by POSIX, but -a
unary isn't. POSIX only defines -a
binary (See test POSIX).
POSIX defines three arguments test
behaviour:
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.
If $1 is '(' and $3 is ')', perform the unary
test of $2. On systems that do not support the XSI option, the results are unspecified if $1 is '(' and $3 is ')'.
Otherwise, produce unspecified results.
So -a
also leads to strange result:
$ [ ! -a . ] && echo true
true
-a
is considered as binary operator in context of three arguments. See Bash FAQ question E1.
POSIX also mentions that -a
is get from KornShell but was changed later to -e
because it makes confusing between -a
binary and -a
unary.
The -e primary, possessing similar functionality to that provided by
the C shell, was added because it provides the only way for a shell
script to find out if a file exists without trying to open the file.
Since implementations are allowed to add additional file types, a
portable script cannot use:
test -b foo -o -c foo -o -d foo -o -f foo -o -p foo
to find out if foo is an existing file. On historical BSD systems, the
existence of a file could be determined by:
test -f foo -o -d foo
but there was no easy way to determine that an existing file was a
regular file. An early proposal used the KornShell -a primary (with
the same meaning), but this was changed to -e because there were
concerns about the high probability of humans confusing the -a primary
with the -a binary operator.
-a
binary is also marked as obsolescent, because it leads to some ambiguous expression, which has greater than 4 arguments. With these >4 arguments expression, POSIX defines the result is unspecified.