Matyas
Matyas

Reputation: 13702

Why does negated file existence check in bash return weird results in case of existing target?

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:

Here is a screenshot of the result:

enter image description here

Notes:

Upvotes: 1

Views: 1415

Answers (4)

Scrutinizer
Scrutinizer

Reputation: 9926

-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..

Upvotes: 3

that other guy
that other guy

Reputation: 123490

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" ]]

Upvotes: 2

jimm-cl
jimm-cl

Reputation: 5422

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.

Upvotes: 2

Christopher C. S. Ke
Christopher C. S. Ke

Reputation: 265

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

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

Upvotes: 1

Related Questions