Saturday, 3 September 2016

Command Chaining with && and ||

Command Chaining with && and ||

We can chain command using the logical AND (&&) operator or the logical OR (||) operator.
They work like this.

&&-operator

The command on the right side of && will only be executed if the command on the left side of && sets and exit code of 0.

||-operator

The command on the right side of || will only be executed if the command on the left side of ||sets an exit code other than 0, i.e. signals an error condition.

Examples

The examples to follow use another method of chaining command, which is the “;” operator. This one simply chains commands disregarding their respective exit code. I use “;” to isolate the workings of && and ||.


Here are some straight forward examples.

Example 1

$ # example 1
$ # simple use of &&
$ mkdir /test && echo "$?: directory created"; echo "$?: this is the second command"
mkdir: cannot create directory ‘/test’: Permission denied
1: this is the second command

Due to the error, the command to the right of && was not executed. The exit code was still 1 when the next echo was executed.

Example 2:

Now the same check with an initial command that works:

$ mkdir /vagrant/test && echo "$?: directory created"; echo "$?: this is the second command"
0: directory created
0: this is the second command


This time the initial command sets exit code 0 which cases the first echo to be executed. The second echo is then executed unconditionally.

Example 3

The combination of && and || is often used to simulate an if-else on one line.
$ # example 3
$ # if-else simulation
$ #
$ # initial command failes
$ mkdir /test && echo "$?: directory created" || echo "$?: directory creation failed"
mkdir: cannot create directory ‘/test’: Permission denied
1: directory creation failed
$ #
$ # initila command succeeds
$ mkdir /vagrant/test && echo "$?: directory created" || echo "$?: directory creation failed"
0: directory created

It really looks like it works if-else like.
But don’t be fooled, it’s only a simulation that breaks down easily, as the next example shows:

Example 4:

In this example, we let the second command, the one that represents the if-case, fail.

$ # example 4
$ # not really if-else
$ mkdir /vagrant/test && mkdir /test || echo "$?: /vagrant/test could not be created"
mkdir: cannot create directory ‘/test’: Permission denied
1: /vagrant/test could not be created


This is what happened:
  • The initial command succeeded, causing the second command to be executed
  • The second command fails, causing the third command (representing the else-case) to be executed

This was probably not what was intended.
But it demonstrates that && and || are simply chaining the commands in a row and execute them based on the exit code of the previous command.
The last example supports this.

Example 5

Here we turned the sequence of && and || around and again let the initial command fail.

$ # example 5
$ mkdir /test || echo "$?: directory creation failed" && echo "$?: directory created"
mkdir: cannot create directory ‘/test’: Permission denied
1: directory creation failed
0: directory created


This is what happened:
  • The initial command failed, causing an exit status of 1, causing the first echo to be executed
  • The first echo completed successfully, causing an exit status of 0, causing the second echo to be executed

Takeaway: && and || are simply chaining commands on condition.

Thursday, 1 September 2016

About the Exit Code

All commands you execute in bash set an exit code.

Use of Exit Codes

Exit codes can be used to manage the flow of control within a bash script.

How to Work with Exit Codes

The exit code of the last command executed, is stored in the special variable “$?”.

Exit codes are in the range of 0 .. 255:
  • 0 indicates that the last command executed successfully.
  • All other values indicate some error condition.


Let’s run some code to see:
  • How Bash initializes the exit code
  • How every command sets the exit code
  • That it makes sense to store an exit code
When a bash script starts, the exit code stored in $? is initialized with 0, i.e "no error".
# show the initial state of $ß
RESULT=$?
echo '$? is initialized with: '$RESULT

Now let's run a command that will produce an error, store the exit code, run some other commands and monitor the exit code along the way:
$ # create an error and store the exit code it produced
$ mkdir /test
mkdir: cannot create directory ‘/test’: Permission denied
$ RESULT=$?
$ # what is the current exit code?
$ echo '  $? is: '$?
  $? is: 0
$ # repeat the error
$ mkdir /test
mkdir: cannot create directory ‘/test’: Permission denied
$ echo '  $? now is: '$?
  $? now is: 1
$ # what is it after the last echo command?
$ echo '  and now it is: '$?
  and now it is: 0
$ # here is the value we stored
$ echo "The exit code wie stored is: "$RESULT
The exit code wie stored is: 1

The interesting thing here is that assigning the exit code to the RESULT variable is a successful command and will reset the exit code to 0 again.
Even using the echo command (which will succeed most of the time) will reset the exit code.

The thing to keep in mind is to store an exit code if you cannot process it immediately, because everything you do after the error occurred will reset the exit code to some new value.

My Linux Bash Board

About the Blog

This is about my personal journey into the world of the Linux Bash shell (it certainly has nothing to do with bashing J).
You will not learn bash programming from this blog as it is no tutorial. There are already so many very good resources around, like those I’m learning from.

What I’m posting here are topics I found particularly interesting or confusing. Things I struggled with, but believe to have finally understood and don’t want to research again.
So they end up here for reference, on my Linux Bash Board.

About the Examples

I’m working on a Windows 10 laptop running a Vagrant powered CentOS 7 image within a VirtualBox. If not stated otherwise, all my example code was run in this environment.

Comments

I appreciate your feedback. Most of all, your corrections and clarifications are most welcome.