89

What function do the -a and -n options perform in the following bash if statement?

if [ -n "$1" -a -n "$2" -a -n "$3" ]; then
    REFNAME=$(basename $3)
else

Are -a and -n so called primaries?

Does -a file mean "True if file exists."?

Cory Klein
  • 51,188
  • 43
  • 183
  • 243
surfi
  • 1,451
  • 2
  • 12
  • 25
  • 2
    -n string True if the length of string is non-zero. -a file True if file exists. – Dr.Bit Sep 12 '19 at 14:24
  • 1
    `[` is a bash command itself. Do `man [`. Search for `-n`. Scroll/search till you see: "-n string True if the length of string is nonzero" – mfaani May 25 '22 at 17:48

2 Answers2

206

-a Links two expressions together in an "and" or "&&" expression. This option is deprecated.

-n Checks if the length of a string is nonzero.

You could translate the test expression into the following pseudocode:

if ( ($1 has nonzero length) and
     ($2 has nonzero length) and
     ($3 has nonzero length) )

There are no checks in that expression for whether the file exists or doesn't exist, only whether the arguments have been supplied to the script.

The arguments -a and -n can be found in the manpage for test

man test

The operator [ ... ] is often used as shorthand for test ... and likely has identical functionality on your system.

Cory Klein
  • 51,188
  • 43
  • 183
  • 243
  • Never expected this question to get so much attention because it is _so specific_. I'm really curious how people keep finding this so useful? – Cory Klein May 04 '18 at 12:29
  • 2
    It's useful because your answer is like the TL;DR version of the accepted answer, for people who want to quickly understand what `-a` and `-n` do without reading a wall of text – adamc May 16 '18 at 02:22
  • 2
    I meant I'm curious how people keep finding this _question_ about `-n` and `-a`. I mean, what are you Googling for? Searching for single character command line arguments... I probably couldn't find this question on Google if I tried. – Cory Klein Jul 09 '18 at 23:37
  • 3
    @CoryKlein, I googled the following: bash command "if -n" – gunit Aug 27 '19 at 17:28
  • 1
    I was looking for examples of 'if' in Bash: `site:stackoverflow.com bash if` – Peter Mortensen Jan 01 '20 at 00:49
  • Worth noting that the logical inverse of `-n` is `-z` so `[ -n "$string" ]` is equivalent to [ ! -z "$string" ]` (`-z` is true if the string is zero length) – razzed Sep 10 '20 at 21:22
  • 1
    @CoryKlein I searched for `bash what is dash n` and got here. – user1717828 Oct 05 '20 at 13:13
  • "The arguments -a and -n can be found in the manpage for test" So useful, thank you! – slax57 Jan 31 '22 at 09:09
  • @CoryKlein I googled 'bash "-n" flag' and this was the second result. – Étienne Aug 22 '22 at 09:40
51

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
sorpigal
  • 25,504
  • 8
  • 57
  • 75
  • 41
    It would be nice if this answer described the behaviour of -n under the sectioned entitled "The behavior of -a and -n". – pamphlet Mar 30 '15 at 15:30
  • 17
    I've read your answer from top to bottom and it doesn't answer the question. We're not interested in nitpicking, it is not what the OP asked. He asked about `-a` and `-n` and I still don't know how `-n` works. – Hexworks Apr 26 '19 at 08:37
  • I will quote from the above: "This will show that `-n` tests the following argument and evaluates to true if it is not an empty string." -- the example also demonstrates this. – sorpigal Apr 28 '19 at 00:39
  • 12
    Why start with a nitpick? Why not answer the question directly up front then go into whatever details are necessary for a deeper understanding of the answer? – jpoveda May 17 '19 at 15:21
  • 1
    'Primary' is a term from parser design. It refers to something at the lowest level of the parse tree: a constant, or identifier, or somesuch. – EML Sep 21 '22 at 16:47