Nitpicking
The switches -a
and -n
are not strictly part of a bash
if
statement in that the if
command does not process these switches.
What are primaries?
I call them "switches", but the bash
documentation that you linked to refers to the same thing as "primaries" (probably because this is a common term used when discussing parts of a boolean expression).
Background and docs
In sh
scripts if
is a command that takes a command as its argument, executes it and tests its return code. If the return code is 0
the block of code following then
is executed up until the closing fi
or (if supplied) the following else
. If the return code was not 0
and an else
statement was supplied then the block of code following else
is executed up until the closing fi
.
You can see this effect by passing if
the command true
or the command false
, which are simple commands that do nothing and return 0
and non-0
respectively.
if true ; then echo true was true ; else echo true was false ; fi
if false ; then echo false was true ; else echo false was false ; fi
In the sample code you provided the command that you're passing to if
is [
, which is also sometimes known as test
. It is this command which takes the switches you're asking about. In bash
the test
command will be a built-in command; try type [
to learn its type. For built-in commands help
will show usage, so also run help [
to see documentation. Your system probably also has a /bin/[
and a /bin/test
and if you man test
you can see the manuals for those. Although the behavior of the built-in test
may not be identical to the behavior documented in the man pages, which is likely more verbose than the simple description you'll get from help [
, it will probably describe the behavior of the built-in [
command fairly accurately.
The behavior of -a and -n
Knowing that the command you're running is test
we can consult help test
or man test
and read its usage. This will show that-n
tests the following argument and evaluates to true if it is not an empty string.
In the documentation of test
you will also see a the switch -e
. This switch tests the following argument and evaluates to true if that argument is a file or directory that exists. More useful still is the -f
switch which evaluates to true if the following argument exists and is a regular file (as opposed to a directory or a block device, or whatever).
The source of your confusion is probably that there can be two forms of -a
: Unary and binary. When -a
is used in a unary context, that is with one following argument but no preceding arguments, it treats its argument as a file and tests for its existence, just like the -e
switch. However, when -a
is used in a binary context, that is with one argument before it and one argument after it, it treats its arguments as other conditions and acts as a boolean AND operator.
In the interests of portability it is important to note that unary -a
is a non-standard extension which won't be found in POSIX. It is available in bash
and ksh
, however, so usage is probably widespread.
Example
cd /tmp
if [ -a test-file ] ; then
echo 1: test-file exists
else
echo 1: test-file missing
fi
touch test-file
if [ -a test-file ] ; then
echo 2: test-file exists
else
echo 2: test-file missing
fi
var=somerthing
if [ -n "$var" -a -a test-file ] ; then
echo variable var is not empty and test-file exists
fi
rm -f test-file