Introduction
This tutorial will introduce you to scripting in a Bash shell, its structure, and how you can get started with it. In this tutorial, I assume that you are already familiar with or have some knowledge of the shell and Linux commands. If you don't, I found a really nice article on Linux commands by ToyinO, you can check it out.
Table of Contents
- What is a Shell Script
- Structure of a Shell Script
- Using Variables
- Basic Operators
- Shell functions
- Conditional Statements for Shell Scripts
- Conclusion
What is a Shell Script
A shell script is a command-line program that contains a series of commands that are executed by an interpreter. It is usually a plain text file that can contain a series of commands that will be run or executed by the Unix/Linux shell one after the other or sequentially. A shell script is great for automating tasks, it can help save time and increase productivity. If you have to repeatedly run a series of commands often, whether simple or complex to accomplish a task, then you can and probably should write a shell script for that task. You can put any command that you can type and run on the command line in a shell script and vice versa. Before you can run a script, you need to have execute permission for that script. You can name your script whatever you like but it is advisable that it be descriptive. You can add an extension on .sh to the name of the script but this is just so that it is clear to everyone that it is a script file, with Linux being an extensionless system, the script will still run without the .sh extension. Shell scripts can be used to automate tasks such as daily backups, installation of packages on multiple servers, troubleshooting, and so on.
Structure of a Shell Script
The first line of a shell script should indicate the interpreter that will be used to execute the script, in this case, I am using Bash. This line starts with something called Shebang, which is a # sign followed by an exclamation mark (!). The Shebang is then followed by the path to the interpreter.
Note - there are no spaces in the Shebang line.
#!/bin/bash
After the Shebang line, you can have comments describing what the script does, the name of the author, and even the day it was created. Anything following a # sign is a comment and is not being executed by the interpreter with exception of the Shebang line. Comments are optional but it is a good practice to include comments in your scripts.
# Name of Script: test.sh
# A simple bash script to illustrate some basic concepts
# Author: Goodness Chris-Ugari
# Date: 16-02-2021
After the comments at the file header with details of the script, you can then have your series of commands to be executed.
#!/bin/bash
# Name of Script: test.sh
# A simple bash script to illustrate some basic concepts
# Author: Goodness Chris-Ugari
# Date: 16-02-2021
# Display Hello, World
echo Hello, world
# Display the present/current working directory
pwd
To run the script above, you type out the path to the file and press enter. In this case, it would be ./test.sh
, assuming that the script is located in our present working directory. When run the above script will print out "Hello, World" to the command line and print out your present working directory on a new line.
Demonstrating the running of a script
Using Variables
Variables are named storage locations. They are are used when you need to store a particular that you can use later. You can declare a variable and assign a value to it in Bash script. The format for declaring a variable is VARIABLE_NAME=value
without spaces on both sides of the declaration. A variable name can be made up of uppercase letters, lowercase letters or a combination of both but remember that Bash is case sensitive. After declaring a variable, you refer to it using the dollar sign ($) followed by the variable name.
# Declare a variable NAME and assign a value to it.
MOOD=Excited!
# Display "I am Excited!"
echo I am $MOOD
I am sure you can guess what the above code would print, I am excited!
, that's right!
Note that you should use double quotes around complex variable values, like those that contain spaces as Bash uses space to separate items. For example MOOD=very excited!
would return an error when the variable $MOOD is used but if we do this MOOD="very excited"
would work as it should.
Command Substitution
You can assign the output of a command (What would have been printed on the screen) to a variable, this is known as command substitution. To do this, place it within brackets preceded by the $ sign.
#The code below will return the number of entries in a directory.
dirContents=$(ls | wc -l)
echo The number of entries in this directory is $dirContents
Special Variables
Special or positional variables are variables that are automatically set for you in Bash. Here are some of them:
- $0 - This contains the name of the script.
- $n - These contain command-line arguments with which a script was called. For example, $1 contains the first argument, $2, the second argument, and so on.
- $# - This contains the number of command-line arguments given to the script
- $* - All the command line arguments.
- $? - The exit status of the last executed command or most recently run script. An exit status of 0 means success while 1 means failure.
- $$ - The process ID of the current script
Basic Operators
In bash, you have access to arithmetic, relational, boolean, string and file test operators.
Arithmetic Operators
Operator | Description | Usage |
+ | Addition | num1 + num2 |
- | Subtraction | num1 - num2 |
* | Multiplication | num1 * num2 |
/ | Division | num1 / num2 |
% | Modulus | num1 % num2 |
= | Assignment | $num = value |
You can use arithmetic operators in bash scripts by using in a few ways, using the let
or the expr
keyword, using the square brackets or double bracket preceded by the $ sign. You can't just try to perform arithmetic operations by typing out the numbers with an arithmetic operator. Try typing 1 + 2
or 1+2
in the command line and you will see that it returns an error. If you try to echo them like so echo 1 + 2
or echo 1+2
, they get treated as strings and will be displayed as 1 + 2
and 1+2
respectively. Study the code snippet below to understand how they are being used.
#!/bin/bash
#
let myVariable=2+3 #If you are declaring the expression without quotes, then you must ensure that the expression doesn't contain spaces.
echo $myVariable #This will output 5
#Using the let command
let "myVariable = 2 + 3" #You can have spaces within quotes.
echo $myVariable # This will output 5
let myVariable++ #Will increment the last value of $myVariable, so $myVariable will now be 6
#Using the expr command
expr 2 + 3 #You must include space when using the expr command and do not enclose the expression in quotes. This line will output the addition of the two numbers.
expr "2 + 3" #Will be treated as a string and will output 2 + 3
expr 2+3 #Will be treated as a string and will output 2+3
#Using brackets
echo $[2+3] #Will work with or without spaces and output the addition of the numbers.
echo $((2+3)) #Will also work with or without spaces.
Note - with the let
command, you have to save the result to a variable while the expr
command outputs the result.
Relational Operators
Operator | Description | Usage |
-eq | Equal to | $num1 -eq $num2 |
-ne | Not equal to | $num1 -ne $num2 |
-gt | Greater than | $num1 -gt $num2 |
-lt | Less than | $num1 -lt $num2 |
-ge | Greater than or equal to | $num1 -ge $num2 |
-le | Less than or equal to | $num1 -le $num2 |
Note - these do not work for string values
Boolean
Operator | Description | Usage |
! | Negation | ! |
-o | Logical OR | conditon1 -or condition2 |
-a (&&) | Logical AND | condition1 -a condition2 |
Note - You can also use || to represent Logical OR and && to represent Logical AND.
String Operators
Operator | Description | Usage |
= | Equal to; Will return true if the strings match | $string1=string2 |
!= | Not equal to; Will return true if the strings do not match | $string1!=$string2 |
-z | Checks if a given string operand size is zero (0). Returns true if it is zero length | -z $string |
-n | Checks if given string operand size is non-zero | -n $string |
File Test Operators
Some Common test operators
Operator | Description | Usage |
-d | Checks if file is a directory | -d $file |
-f | Checks if file is an ordinary file | -f $file |
-p | Checks if file is a named pipe | -p $file |
-r | Checks if file is readable | -r $file |
-w | Checks if file is writable | -w $file |
-x | Checks if file is executable | -x $file |
-s | Checks if file has a size greater than zero (0) | -s $file |
-e | Checks if file exists | -e $file |
Shell loops
Loops are used to execute a set of commands repeatedly.
For Loop
This type of loop repeats a set of commands for every item in a list.
for var in <list>
do
<command>
done
Example
#!/bin/bash
#This will print numbers 1 to 5
for value in {1..5}
do
echo $value
done
While Loop
This loop executes a set of commands while a given condition is true, so the loop will stop when the condition becomes false.
Syntax
while [ <condition> ]
do
<command>
done
Example
#Will print numbers 1 to 5
count=1
while [ $count -le 5 ]
do
echo $count
((count++)) #Will increment count by 1 after every loop
done
Until Loop
This loop will execute a set of commands until a given condition becomes true.
until [ <condition> ]
do
<command>
done
Example
#Will print numbers 1 to 5
count=1
until [ $count -gt 5 ] #Loop will stop one count is greater than 5
do
echo $count
((count++)) #Will increment count by 1 after every loop
done
Shell functions
A function is a reusable block of a set of commands. Functions help you to not repeat yourself as you can write a function to perform a specific task and then use it many times whenever and wherever you need it.
Function Syntax
#Without the function keyword
function_name () {
<commands>
}
Or
#With the function keyword
function function_name {
<commands>
}
Example
#!bin/bash
#A function that prints out the first argument supplied to it
function printArg () {
echo The first argument is $1
}
#Function call with an argument
printArg "Hello World"
#The output of the function above will be "The first argument is Hello World"
Both methods of declaring functions are valid and will behave the same so whichever you decide to use is based on your preference. If you are familiar with other programming languages that also have brackets in their function declaration, you would think the brackets are for arguments but in bash, it is not so. The brackets are merely for decoration and nothing should be placed in them.
From the code above, you can see that arguments are provided directly after the function name when you call the function.
Note - you can't call a function before you have declared it.
Conditional Statements for Shell Scripts
Conditional statements allow you to make decisions based on a condition or test within your shell script.
If Statements
This will perform a given set of instructions or commands if the test or condition provided is true, the set of instructions won't be carried out otherwise.
Syntax
if [ <condition/test> ]
then
<command>
fi
If Else Statements
This works just like the basic if statements explained above but also provides room for a condition to be performed if the condition is not true. If the condition is not true, the command or set of commands () between else
and fi
will be executed.
Syntax
if [ <condition/test> ]
then
<command1>
else
<command2>
fi
Example
#!bin/bash
#This script will take 2 numbers as command-line arguments. It will print to the screen the larger of the two numbers.
if [ $1 -gt $2 ]
then
echo $1
else
echo $2
fi
Output
If Elif Else
This is used for multiple conditions with different outcomes.
Syntax
if [ <condition1> ]
then
<command1>
elif [ <condition2> ]
then
<command2>
elif [ <condition3> ]
then
<command3>
else
<command>
fi
Example A script that will print a message based upon which day of the week it is.
#!/bin/bash
#script to print a message based upon which day of the week it is.
day_of_the_week=$(date +%u)
if [ $day_of_the_week -eq 1 ]
then
echo Today is Monday, aargh!
elif [ $day_of_the_week -eq 2 ]
then
echo Today is Tuesday
elif [ $day_of_the_week -eq 3 ]
then
echo Today is Wednesday
elif [ $day_of_the_week -eq 4 ]
then
echo Today is Thursday
elif [ $day_of_the_week -eq 5 ]
then
echo Today is Friday, TGIF!
elif [ $day_of_the_week -eq 6 ]
then
echo Today is Saturday
elif [ $day_of_the_week -eq 7 ]
then
echo Today is Sunday
else
echo Something is wrong
fi
Output
Note - you can change your system time to see the different outputs else it will only display the output for your present day.
You can have as many elif
branches as you want. It is valid to have an if statement inside another one, that is nesting if statements.
Note - You have to include spaces in the square bracket that contains the condition as seen in the examples else an error will be return.
Case Statements
This should be used in cases that might lead to a long string of if and elif statements, case statements present it in a much neater way.
Syntax
Case <variable> in
<pattern1>)
<command>
;;
<pattern2>)
<command2>
;;
esac
Example
#!/bin/bash
echo Which color do you prefer? Blue, Green or Yellow? #This will be printed first when you run the script.
read color #Prompt to accept input
case $color in #Compare using the value entered for color at the prompt********
Blue)
echo Feeling blue today?
;;
Green)
echo The land is green!
;;
Yellow)
echo It is going to be a sunny day!
;;
*)
echo Try Again
;;
esac #Indicates the end of the case statement
Output
Conclusion
Bash/Shell Scripting is vast and this article is just to help understand the basics to get started. With your knowledge of Linux commands, you can do really useful things with bash scripting and automate repetitive tasks.
Thank you for reading, I hope you find this guide useful ๐.