Itai Ganot
Itai Ganot

Reputation: 6303

Shell Script: What's the difference between using test and if statement?

What's the difference between

[ -e /usr/local/nagios ] && echo yes

and

if [ -e /usr/local/nagios ]; then echo yes
fi

And when is it right to use any of them?

Let's say I want to test if Nagios was compiled from source or installed through yum (the default installation location from source is /usr/local/nagios and through YUM it's /etc/nagios) - then I will know where the plugins folder resides and it will allow me to pull the plugins from the Nagios server to the Nagios client and place them in the right directory. So which approach is the best to achieve this goal?

Thanks in advance

Upvotes: 4

Views: 14652

Answers (3)

Ross Patterson
Ross Patterson

Reputation: 5742

Adding something practical to the other technical answers here, one reason to use if ...; then do-stuff; fi over ... && do-stuff, regardless of whether we use test or [ ] for the condition, is the resulting exit code, and exit codes should usually express success or failure:

$ touch foo.txt
$ if test -e foo.txt; then echo "do stuff"; fi
do stuff
$ echo $?
0
$ test -e foo.txt && echo "do stuff"
do stuff
$ echo $?
0
$ if test -e bar.txt; then echo "do stuff"; fi
$ echo $?
0
$ test -e bar.txt && echo "do stuff"
$ echo $?
1

In other words, using if ... expresses that the condition being false is not a failure but an expected and perfectly fine thing to happen, it just means don't run do-stuff. Using ... && expresses that the condition being false not only means don't run do-stuff, it means the net result is a failure, that something has gone wrong.

While it's true that most things you can do with if ... you can do with &&, || and (...), it's much harder to understand the intention when read by a human, and code is for both machines and humans:

$ (test -e foo.txt && echo "do stuff") || true
do stuff
$ echo $?
0
$ (test -e bar.txt && echo "do stuff") || true
$ echo $?
0

And yes, we don't need ( ... ) here, but its even harder to understand the intention without them. Is the || for if do-stuff fails or if the condition is false? None of the time and effort spent reasoning through such things or looking for context clues is necessary to understand the intention of if .... This becomes more and more true the more complicated the conditions. Imagine adding multiple "else if ..." sub-conditions and a final "else" clause using && and ||.

Upvotes: 2

Dettorer
Dettorer

Reputation: 1336

[ is usually an other name for the command test, just expecting a ] as last argument. You could actually write the two commands:

test -e /usr/local/nagios && echo yes

and

if test -e /usr/local/nagios; then echo yes; fi

test and [ are just shell commands performing checks and returning 0 or 1, that's why you can use it like this [ -e file ] && echo exists (or test -e file && echo exists).

When writing a script a few line long, I usually find the use of if clearer and more explicit.

As of your other question, relying on hard coded paths is usually a bad idea (you can install from source to another directory and yum may install nagios somewhere else in the future or depending on some configuration). I suggest you try querying yum to see if it has nagios installed (with yum info nagios or yum list installed | grep nagios for example). Then, if nagios wasn't installed with yum, but the binary is in your PATH, you can try which nagios which will give you the full path of the nagios binary.

Upvotes: 9

Arjun Mathew Dan
Arjun Mathew Dan

Reputation: 5298

Option1:

[ -e /usr/local/nagios ] && echo yes

Here, you are using the Logical AND operator(&&). The second operand will be evaluated only if the first one returns true. At first "[ -e /usr/local/nagios ]" will be evaluated. That is, checks if /usr/local/nagios exists. If it doesn't exist, the next part "echo yes" will not be evaluated. So, effectively "echo yes" will be done only if /usr/local/nagios exists, thus yes will be printed out. else it will not.

Option2:

if [ -e /usr/local/nagios ]
then
  echo yes
fi

This is just another way of doing the same thing. Here, we check if /usr/local/nagios exists. If it exists, then print yes. else do nothing.

Eventhough the first option looks smarter, considering readability, I would go for option 2. Personal choice i would say.

Upvotes: 3

Related Questions