Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What do the -n and -a options do in a bash if statement? [duplicate]

Tags:

bash

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

like image 314
surfi Avatar asked Feb 15 '13 17:02

surfi


2 Answers

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

like image 107
Cory Klein Avatar answered Sep 27 '22 19:09

Cory Klein


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 
like image 38
sorpigal Avatar answered Sep 27 '22 19:09

sorpigal