Thursday 18 April 2013

Understanding the AND && and the OR || Shell operators

The UNIX/Linux shell has the very handy AND operator ("&&") and the OR operator ("||").   When you first encounter these, they can be difficult to understand.   But once you understand the logic behind the way they work they are much easier to use.

The shell is lazy.  If you have two questions for it:  question1 and question2, and you ask it "Is question1 OR question2 True?".  The shell will figure out the answer for question1, and if the answer is true, it won't even look at question2 at all.   This is because we asked if one OR the other is true.   Since the first one is true, without even looking at question2 it can answer that YES, "Question1 OR question2 is true". 

A similar concept applies to the "AND" statement.   If you asked:  "Is question1 AND question2 True?".   The shell will figure out the answer for question1, and if it is false, it doesn't even look at question2 at all.   This is because we asked if they were BOTH true and since the first one is false, there is no way they can both be true, so it won't even bother looking at the second question at all.

If your not familiar with return codes on UNIX/Linux, a "0" return code is "TRUE" and a non-zero return code is "FALSE".  Every command you run has a return code when it exits.

Due to this feature of these operators, it can open up some interesting possibilities.  Here are a few examples of how we can take advantage of this:
id newuser || mkuser newuser
In this example the first command run is the "id" command.  The id command returns a "TRUE" exit code ("0") if the account exists, and a "FALSE" exit code ("1") if the account doesn't exist. 

If the "newuser" account doesn't exist, when this command is run the "id" command will return false.   Since we are asking "OR" in this statement, the shell MUST run the second command to see if it is true since the first command was false.   The end effect of this is the "mkuser" command will only be run if the "newuser" account doesn't exist. 

If the "newuser" account does exist, when this command is run the "id" command will return true.  Since we are asking "OR" the shell doesn't need to run the second command at all (mkuser).   So if the account does exist, the mkuser command is NOT run.

Here is another example of how to delete a directory if it exists:
 [ -d /tmp/test ] && rm -rf /tmp/test
In this example the first command ("[ -d /tmp/test]") returns TRUE if the directory exists, and FALSE if the directory does not exist.

If the directory does exist, the first command returns true.   Since we specified "AND" the shell must run the second command to determine if both the first and second commands are true.  The result of this is the directory is deleted if it exists.

If the directory does not exist, the first command returns false.   Since we specified "AND", and the shell knows the first command is false, there is no need for it to run the second command.  So if the directory does not exist, it will not run the command to delete it.  

The "&&" and "||" operators can also be used in a more traditional way.   For example, you can check to see if 2 files exist using "&&" and an if statement like this:
if [ -e /tmp/file1 ] && [ -e /tmp/file2 ]; then
      echo both files exist
fi

The if statement is only run if both files exist.

Below are tables that visually show how these operators work.   If it says "TRUE" it means that command returned a "0" return code.   If it says "FALSE" it means that command returned non-zero return code.   If it says "NOT RUN" it means the shell can answer the question without running this command so it isn't run.   The "Overall return code" is the return code the entire statement evaluates to.

GREEN=Command RunYellow = Command NOT run
First CommandOperatorSecond CommandOverall Return code
TRUE&&TRUE0 TRUE
TRUE&&FALSE1 FALSE
FALSE&&NOT RUN1 FALSE
GREEN=Command RunYellow = Command NOT run
First CommandOperatorSecond CommandOverall Return code
TRUE||NOT RUN0 TRUE
FALSE||TRUE0 TRUE
FALSE||FALSE1 FALSE

It is also possible to have more than 2 commands strung together in these kind of statements (i.e.  command1 || command2 && command3).   Here is a table that shows how this looks:

GREEN=Command RunYellow = Command NOT run 
First CommandOperatorSecond CommandOperatorThird CommandOverall Return code
TRUE&&TRUE&&TRUE0 TRUE
TRUE&&TRUE&&FALSE1 FALSE
TRUE&&FALSE&&NOT RUN1 FALSE
FALSE&&NOTRUN&&NOT RUN1 FALSE
GREEN=Command RunYellow = Command NOT run 
First CommandOperatorSecond CommandOperatorThird CommandOverall Return code
TRUE||NOT RUN||NOT RUN0 TRUE
FALSE||TRUE||NOT RUN0 TRUE
FALSE||FALSE||TRUE0 TRUE
FALSE||FALSE||FALSE1 FALSE
GREEN=Command RunYellow = Command NOT run 
First CommandOperatorSecond CommandOperatorThird CommandOverall Return code
TRUE||NOT RUN&&TRUE0 TRUE
TRUE||NOT RUN&&FALSE1 FALSE
FALSE||TRUE&&TRUE0 TRUE
FALSE||TRUE&&FALSE1 FALSE
FALSE||FALSE&&NOT RUN1 FALSE
GREEN=Command RunYellow = Command NOT run 
First CommandOperatorSecond CommandOperatorThird CommandOverall Return code
TRUE&&TRUE||NOT RUN0 TRUE
TRUE&&FALSE||TRUE0 TRUE
TRUE&&FALSE||FALSE1 FALSE
FALSE&&NOT RUN||TRUE0 TRUE
FALSE&&NOT RUN||FALSE1 FALSE

Conclusion

The "&&" and "||" operators are very handy operators to use.   They can save you time and make shell scripting easier.  

0 blogger-disqus:

Post a Comment