Bash – the difference of -a and -e in bash’s conditional expressions

bashshelltest

From man bash:

CONDITIONAL EXPRESSIONS
[...]
       -a file
              True if file exists.
[...]
       -e file
              True if file exists.
  1. So what is the difference between [ -a $FILE ] and [ -e $FILE ], if any?
  2. If there is no real difference, why do two flags for the same purpose exist?

Best Answer

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.