Bash Scripting For Beginners – Part 2

Exit Status & Return Code

In this lesson you will learn:

  • How to check exit status of a command.
  • How to make decision based on the status.
  • How to use exit statuses in your own script.

Every time a command is executed it returns exit status, the exit status which is sometimes called return code or exit code is an integer ranging from 0 to 255.

By convention command execute successfully return zero exit status, if some sort of error encountered then a non-zero exit status is returned.

These return code in a script can be used as error checking, it can be a simple check like checking zero return code or can be more complex like checking for a specific error code.

If you want to find what is the various exit status mean, you have to console the documentation of the given command and look at its source code.

You can use man command or info command to read the documentation for most command on your system

  • Every command returns exit status.
  • Range from 0 to 255.
  • 0 = success.
  • Other than 0 = error condition.
  • Use for error checking.
  • Use man and info to find meaning of exit status.

Checking the Exit Status:

  • $? Contains the return code of the previously executed command.
$ ls /not/here
echo "$?"

Output: 2

In this example the “ls” command is called with the path to a file it does not exit, the exit status of this command is 2, remember that non-zero exit code indicates some sort of error.

 

You can use an exit status of a command to make a decision or performing different action based on the exit status.

Example:

HOST="google.com"
ping -c 1 $HOST
if [ "$?" -eq "0" ]
then
echo "$HOST reachable"
else
echo "$HOST unreachable"
fi

In this example of shell script, we use the ping command to test our network connectivity to google.com.

-c option of ping command simply tells ping to send just one packet.

After the ping command is executed we checked the exit status. If the exit status is equal to zero, we echo to the screen that google.com is reachable if the status is not equal to zero then we echo to the screen that google.com is unreachable.

Example:

HOST="google.com"
ping –c 1 $HOST
if [ "$?" –ne "0" ]
then
echo "$HOST unreachable"
fi

This example just checks for the error condition and the if statement looks for a non-zero exit status. Then we echo the HOST is unreachable. If the ping command succeeds and returns a zero exit status then the echo command statement is not executed.

Example:

HOST="google.com"
ping –c 1 $HOST
RETURN_CODE=$?
if [ "RETURN_CODE" –ne "0" ]
then
echo "$HOST unreachable"
fi

We can assign return code of a command to a variable and use that variable later in the script. In this example the value of $? is assigned to the RETURN_CODE variable, so the RETURN_CODE contains the exit status of the ping command.

 

&& and ||

In addition to using if statement with exit status you can use logical (&&=AND) and (||=OR).

The double && represent AND, and the double pipe represent OR, you can chain together multiple commands with either AND or OR.

The command following double && will only execute if the previous command succeeds.

Another way the if the command following the double || will only run if the previous command exit with the zero exit status.

Example:

&& = AND

mkdir /tmp/bak && cp test.txt /tmp/bak/

|| = OR

cp test.txt /tmp/bak/ || cp test.txt /tmp

In the example above, mkdir /tmp/bak is executed. If it succeeds and returns a zero exit status then and only then the cp command is executed. In this example, you can see there is no need for the cp command to be executed if the directory wasn’t created.

  • The command following the double pipe (||) will only execute if the previous command fails, if the first command returns non zero exit status then the next command is executed.
  • In the OR example the first cp command i.e. cp test.txt /tmp/bak/ is executed. If it succeeds, the next cp command is not executed. In this example, if the first cp command succeeds then we have successfully created the backup copy of test.txt. So there is no need for another backup copy of that file. If the first command fails then the second command is executed.

Let’s revisit our earlier example:

#!/bin/bash
HOST="google.com"
ping -c 1 $HOST  && echo "$HOST reachable."

Instead of using if statement here we are using AND. In this example if the ping command exits with a zero exit status then google.com reachable will be echoed to the screen.

#!/bin/bash
HOST="google.com"
ping –c 1 $HOST  || echo "$HOST unreachable."

Here we are using OR instead of an if statement. In this example, if the ping command fails then google.com unreachable will be echoed to the screen. If the ping command succeeds then the echo statement will not be executed.

The semicolon:

If you want to chain multiple command together on a single line, you can do that by separating those command with semicolon.

A semicolon doesn’t check the exit status of the previous command, the command following a semicolon will always get executed no matter if the previous command fails or succeeds.

In essence separating commands with a semicolon is same as putting those commands in a different line.

For example:

cp test.txt /tmp/bakup ; cp test.txt /tmp
# Same as
cp test.txt /tmp/bakup
cp test.txt /tmp

Exit Command:

You can control the exit status of your shell script by using the exit command. Simply use the exit command in your script number range from 0 to 255.

If you don’t specify the return code with the exit command then the exit status of the previously executed command used as the exit status.

  • Explicitly define the return code.
  • exit 0
  • exit 1
  • exit 2
  • exit 255
  • etc….

The default value is that of the last command executed.

You can use exit command anywhere in your shell script whenever the exit command is reached, your shell script will stop running.

For example:

#/bin/bash
HOST="google.com"
ping –c 1 $HOST
if [ "$?" –ne 0 ]
then
  echo "$HOST unreachable"
  exit 1
fi
exit 0

In this example we are controlling the exit status of our script with the exit command. If the ping command succeeds then the return code of 0 is received and if the ping command fails then the non-zero exit status is received. The exit 1 command will stop the execution of the script and return the exit status 1.

Since you are controlling the exit status you can have a significant meaning return code of 1 means one type of error occurred and return code of 2 means different type of error occurred.

 

Functions Part-1

What you will learn:

  • Why to use functions.
  • How to create them.
  • How to use them.
  • Variable scope.
  • Function parameters.
  • Exit status and return code.

Why use functions?

Here is a concept in computer programming and development known as DRY (don’t repeat yourself).

Functions are allowed to write a block of code once and use it many times instead of repeating several lines of the code each time you need to perform a particular task. Simply call the function that contain that code.

This helps in reducing the length of your script and also gives you a single place to change, test, troubleshoot and document the given task.

  • Functions make your script easier to maintain in the long run.
  • If you’re repeating yourself, use a function.
  • Reusable code
  • Must be defined before code
  • Has parameter support.

Creating a function:

Two ways to create a function in a shell script:

The first way to explicitly use the keyword function then followed by the function name and a set of parenthesis next is the opening curly brace the code or commands that follows will be executed when the function is called to end or close your function use a closing curly brace.

function function-name () {
                # code goes here.
}

The second way to declare a function is exactly like the first except that you do not use a keyword in your declaration everything else stays the same.

function-name () {
                # code goes here.
}

Calling a function:

To call or execute the function simply write its name in a line in the script after you define a function, it acts any other command you can use in your shell script. When calling a function do not use parenthesis simply place the function name in a line and it will execute that function.

#!/bin/bash
function hello() {
                echo “Hello!”
}

When you run this script, the word “Hello” displays on the screen.

Functions can call other functions:

In the below example a hello function and a now function are declared. When the hello function is called, it prints “Hello” to the screen and then it calls the now function which prints the current time to the screen.

#!/bin/bash
function hello() {
                echo “Hello!”
                now
}
function now() {
                echo “It’s $(date +%r)”
}

Note: You may call that the now function is defined after the hello function. The now function actually gets read into the script before the hello function is called. So in the order for execution, it is defined before its use.

Do Not do this…

Function which prints the current time to the screen.

#!/bin/bash
function hello() {
                echo “Hello!”
                now
}
function now() {
                echo “It’s $(date +%r)”
}

If you run above script, it will throw an error stating that now wasn’t found, this is because “Hello” gets executed before the now function was declared or read into the script and this is the main point of scripting language that they are not pre-compiled .

In scripts, the command/component read from top to bottom. It’s a best practice to place all your function at the top in your script. This ensures they are all defined before they are used.

Positional Parameter:

Like shell script themselves, functions can accept parameters also like shell scripts. You can access the values of those passed in parameter using $1,$2 etc.

You can even access all the parameters passed into the function using [email protected]

Just like shell script $0 is still the name of the script itself, so you can access the name of the function using $0.

Example:

#!/bin/bash
function hello() {
                echo “Hello $1”
}

Output is – Hello TechnicalMint

In this example, the hello function is called with the argument TechnicalMint. This means the content of the $1 inside the hello function are TechnicalMint.

#!/bin/bash
function hello() {
                for NAME in [email protected]
                do
                                echo “Hello $NAME”
                done
}

This script will loop through each of the parameters passed to the hello function and echo hello will be followed by the parameters. The output of this script will be three line.

Output:

# Hello TechnicalMint

# Hello script

# Hello function

Variable Scope:

By default, all variables are global. This means that the variables and their values can be accessed anywhere in the script including in any function but the variables has to be defined before it can be used.

Example:

GLOBAL_VAR=1
# GLOBAL_VAR is available in the function
my_function

In this example variable GLOBAL_VAR is defined before the function is called. In this case, the variable GLOBAL_VAR can be accessed in the function.

Example 2: (opposite)

# GLOBAL_VAR is not available in the function.
my_function
GLOBAL_VAR=1

In this example the variable GLOBAL_VAR is defined after the function is called. It is not available in the function.

If the global variable is defined within a function it is not available outside that function until the function is called and executed.

#!/bin/bash
my_function() {
                GLOBAL_VAR=1
}
# GLOBAL_VAR is not available yet.
echo $GLOBAL_VAR
my_function
# GLOBAL_VAR is now available.
echo $GLOBAL_VAR

In this example, the first echo statement simply prints a blank line, next the my_function function is called. Now a value gets assigned to the variable GLOBAL_VAR. The echo statement after the function is called and will print  “1” because that is the value now assigned to the variable GLOBAL_VAR.

Local Variable:

A local variable is variable that can only be accessed within the function in which it is declared.

Use the local keyword before the variable name and only use the local variable keyword when the first time variable used.

local LOCAL_VAR=1

It’s a best practice to keep variables local in functions.

 

That’s it on this article as of now. Hope you liked it. Please share it across if you think it’s good and share your feedback in the comment section below. Thanks for you support! Stay healthy and safe!

Leave a Reply

Your email address will not be published. Required fields are marked *