Bash if -a vs -e option

bash

Both about -a and -e options in Bash documentation is said:

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

Trying to get what the difference is I ran the following script:

resin_dir=/Test/Resin_wheleph/Results

if [ -e ${resin_dir} ] ; then
    echo "-e ";
fi

if [ ! -e ${resin_dir} ] ; then
    echo "! -e";
fi

if [ -a ${resin_dir} ] ; then
    echo "-a";
fi

if [ ! -a ${resin_dir} ] ; then
    echo "! -a";
fi

/Test/Resin_wheleph/Results exists and is a directory. And this is what I get:

-e
-a
! -a

which seems to be a little strange (notice -a and ! -a). But when I use double brackets (e. g. if [[ -e ${resin_dir} ]]) in the similar script it gives reasonable output:

-e
-a

So:

  1. What is a difference between -a and -e options?
  2. Why -a produces a strange result when used inside single brackets?

Best Answer

I researched, and this is quite hairy:

-a is deprecated, thus isn't listed in the manpage for /usr/bin/test anymore, but still in the one for bash. Use -e . For single '[', the bash builtin behaves the same as the test bash builtin, which behaves the same as /usr/bin/[ and /usr/bin/test (the one is a symlink to the other). Note the effect of -a depends on its position: If it's at the start, it means file exists. If it's in the middle of two expressions, it means logical and.

[ ! -a /path ] && echo exists doesn't work, as the bash manual points out that -a is considered a binary operator there, and so the above isn't parsed as a negate -a .. but as a if '!' and '/path' is true (non-empty). Thus, your script always outputs "-a" (which actually tests for files), and "! -a" which actually is a binary and here.

For [[, -a isn't used as a binary and anymore (&& is used there), so its unique purpose is to check for a file there (although being deprecated). So, negation actually does what you expect.