1

I wish to perform an action if a file does not exists in bash with the following command:

if [ ! -a $HOME/.some_directory ] ; then 
     # do something
fi

However the #do something part is always executed regardless of the existence of $HOME/.some_directory.

I've created a small test where I have tried all cases:

  • nonexistent directory check
  • negated nonexistent directory check
  • existent directory check
  • negated existent directory check ( this is the only one returning an "invalid" result) - or I am doing something wrong

Here is a screenshot of the result:

enter image description here

Notes:

Community
  • 1
  • 1
Matyas
  • 13,473
  • 3
  • 60
  • 73

4 Answers4

3

-a as a test if a file exists, is a unary expression ( one-sided ) is a remnant of ksh86 (KornShell 86). It has become obsolete in more modern, derivative shells and has been replaced by -e which is part of the POSIX standard, but in many shells it is still a synonym of -e for backwards compatibility.

-a can also be used a binary expression (two sided) and then it means an AND logical operator (which is also obsolescent). Here -a is interpreted this way because there is a ! symbol in front of it and a string behind it. Both sides evaluate to true, so by using AND the outcome then becomes logically true.

Using -e fixes this since it cannot be interpreted in another way.

Another way would have been to negate that outcome of the test command like so:

if ! [ -a $HOME/.some_directory ] ; then 

or use parentheses for grouping:

if [ ! \( -a $HOME/.some_directory \) ] ; then

But at any rate it is better to stick with operands that are not deprecated / obsolescent..

Scrutinizer
  • 9,608
  • 1
  • 21
  • 22
2

What happens if you try -d instead of -a?

[ -d FILE ] True if FILE exists and is a directory.

~ http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html


Also, seems like -a is deprecated - please review this StackOverflow thread for details.

Community
  • 1
  • 1
jimm-cl
  • 5,124
  • 2
  • 25
  • 27
2

This behavior is specified in POSIX:

3 arguments:

  • If $2 is a binary primary, perform the binary test of $1 and $3.

In your case, $2 is a -a which is a binary primary operator, so $1 and $3 are treated as binary tests. Single words are tested as if with -n ("is non-empty string").

This means that your test is equivalent to:

[[ -n "!" && -n "$HOME/.some_directory" ]]
that other guy
  • 116,971
  • 11
  • 170
  • 194
1

You put a wrong operator; "-a" means AND.

You need "-e" to check if a file exists.

  • You are right, with `-e` works the right way. But then why does [this guide](http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html) begin with this example: `[ -a FILE ] True if FILE exists.` ? Are they wrong? (PS. I can see they also list `-e` with the same explanation) – Matyas Jun 26 '14 at 15:37
  • He described in the very beginning; he performed an action to check if a file doesn't exist and then... – Christopher C. S. Ke Jun 26 '14 at 15:40
  • You pointed me in the right direction (`-e`) (+1 for that) but the actual answer to '*why*' was given by `that other guy`. Thank you – Matyas Jun 27 '14 at 07:22