shell scripting
Bash shell
The default shell for many Linux distros is the GNU Bourne-Again Shell (bash). Bash is succeeded by Bourne shell (sh
).
When you first launch the shell, it uses a startup script located in the .bashrc
or .bash_profile
file which allows you to customize the behavior of the shell.
When a shell is used interactively, it displays a $
when it is waiting for a command from the user. This is called the shell prompt.
[username@host ~]$
If shell is running as root, the prompt is changed to #
. The superuser shell prompt looks like this:
[root@host ~]#
Environment
Login shells read one or more startup files as shown below:
File | Contents |
---|---|
/etc/profile |
A global configuration script that applies to all users. |
~/.bash_profile |
A user's personal startup file. Can be used to extend or override settings in the global configuration script. |
~/.bash_login |
If ~/.bash_profile is not found, bash attempts to read this script. |
~/.profile |
If neither ~/.bash_profile nor ~/.bash_login is found, bash attempts to read this file. This is the default in Debian-based distributions, such as Ubuntu. |
Non-login shell sessions read the following startup files:
File | Contents |
---|---|
/etc/bash.bashrc |
A global configuration script that applies to all users. |
~/.bashrc |
A user's personal startup file. Can be used to extend or override settings in the global configuration script. |
In addition to reading the startup files above, non-login shells also inherit the environment from their parent process, usually a login shell.
Take a look at your system and see which of these startup files you have. Remember— since most of the file names listed above start with a period (meaning that they are hidden), you will need to use the “-a” option when using ls.
The ~/.bashrc
file is probably the most important startup file from the ordinary user’s point of view, since it is almost always read. Non-login shells read it by default and most startup files for login shells are written in such a way as to read the ~/.bashrc
file as well.
If we take a look inside a typical .bash_profile
(this one taken from a CentOS system), it looks something like this:
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/bin
export PATH
Lines that begin with a “#” are comments and are not read by the shell. These are there for human readability. The first interesting thing occurs on the fourth line, with the following code:
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
This is called an if compound command, which we will cover fully in a later lesson, but for now we will translate:
If the file "~/.bashrc" exists, then read the "~/.bashrc" file.
We can see that this bit of code is how a login shell gets the contents of .bashrc
. The next thing in our startup file does is set the PATH variable to add the ~/bin
directory to the path.
Lastly, we have:
export PATH
The export
command tells the shell to make the contents of the PATH variable available to child processes of this shell.
Scripts start with a bash bang.
Scripts are also identified with a shebang
. Shebang is a combination of bash #
and bang !
followed the the bash shell path. This is the first line of the script. Shebang tells the shell to execute it via bash shell. Shebang is simply an absolute path to the bash interpreter.
Below is an example of the shebang statement.
#! /bin/bash
The path of the bash program can vary. We will see later how to identify it.
How to Create Your First Bash Script
Let's create a simple script in bash that outputs Hello World
.
Create a file named hello_world.sh
touch hello_world.sh
Find the path to your bash shell.
which bash
Write the command.
We will echo
"hello world" to the console.
Our script will look something like this:
#! usr/bin/bash
echo "Hello World"
Run the script.
You can run the script in the following ways:
bash hello_world.sh
.
The Basic Syntax of Bash Scripting
How to define variables
We can define a variable by using the syntax variable_name=value
. To get the value of the variable, add $
before the variable.
#!/bin/bash
# A simple variable example
greeting=Hello
name=Tux
echo $greeting $name
Arithmetic Expressions
Below are the operators supported by bash for mathematical calculations:
OPERATOR | USAGE |
---|---|
+ |
addition |
- |
subtraction |
* |
multiplication |
/ |
division |
** |
exponentiation |
% |
modulus |
Numerical expressions can also be calculated and stored in a variable using the syntax below:
var=$((expression))
Let's try an example.
#!/bin/bash
var=$((3+9))
echo $var
Fractions are not correctly calculated using the above methods and truncated.
For decimal calculations, we can use bc
command to get the output to a particular number of decimal places. bc
(Bash Calculator) is a command line calculator that supports calculation up to a certain number of decimal points.
echo "scale=2;22/7" | bc
Where scale
defines the number of decimal places required in the output.
How to read user input
Sometimes you'll need to gather user input and perform relevant operations.
In bash, we can take user input using the read
command.
read variable_name
To prompt the user with a custom message, use the -p
flag.
read -p "Enter your age" variable_name
Example:
#!/bin/bash
echo "Enter a numner"
read a
echo "Enter a numner"
read b
var=$((a+b))
echo $var
Numeric Comparison logical operators
Comparison is used to check if statements evaluate to true
or false
. We can use the below shown operators to compare two statements:
OPERATION | SYNTAX | EXPLANATION |
---|---|---|
Equality | num1 -eq num2 | is num1 equal to num2 |
Greater than equal to | num1 -ge num2 | is num1 greater than equal to num2 |
Greater than | num1 -gt num2 | is num1 greater than num2 |
Less than equal to | num1 -le num2 | is num1 less than equal to num2 |
Less than | num1 -lt num2 | is num1 less than num2 |
Not Equal to | num1 -ne num2 | is num1 not equal to num2 |
Syntax:
if [ conditions ]
then
commands
fi
Example:
Let's compare two numbers and find their relationship:
read x
read y
if [ $x -gt $y ]
then
echo X is greater than Y
elif [ $x -lt $y ]
then
echo X is less than Y
elif [ $x -eq $y ]
then
echo X is equal to Y
fi
Conditional Statements (Decision Making)
Conditions are expressions that evaluate to a boolean expression (true
or false
). To check conditions, we can use if
, if-else
, if-elif-else
and nested conditionals.
The structure of conditional statements is as follows:
if...then...fi
statementsif...then...else...fi
statementsif..elif..else..fi
if..then..else..if..then..fi..fi..
(Nested Conditionals)
Syntax:
if [[ condition ]]
then
statement
elif [[ condition ]]; then
statement
else
do this by default
fi
To create meaningful comparisons, we can use AND -a
and OR -o
as well.
The below statement translates to: If a
is greater than 40 and b
is less than 6.
if [ $a -gt 40 -a $b -lt 6 ]
Example: Let's find the triangle type by reading the lengths of its sides.
read a
read b
read c
if [ $a == $b -a $b == $c -a $a == $c ]
then
echo EQUILATERAL
elif [ $a == $b -o $b == $c -o $a == $c ]
then
echo ISOSCELES
else
echo SCALENE
fi
Looping and skipping
For loops allow you to execute statements a specific number of times.
Looping with numbers:
In the example below, the loop will iterate 5 times.
#!/bin/bash
for i in {1..5}
do
echo $i
done
Looping with strings:
We can loop through strings as well.
#!/bin/bash
for X in cyan magenta yellow
do
echo $X
done
While loop
While loops check for a condition and loop until the condition remains true
. We need to provide a counter statement that increments the counter to control loop execution.
In the example below, (( i += 1 ))
is the counter statement that increments the value of i
.
Example:
#!/bin/bash
i=1
while [[ $i -le 10 ]] ; do
echo "$i"
(( i += 1 ))
done
Reading files
Suppose we have a file sample_file.txt
We can read the file line by line and print the output on the screen.
#!/bin/bash
LINE=1
while read -r CURRENT_LINE
do
echo "$LINE: $CURRENT_LINE"
((LINE++))
done < "sample_file.txt"
How to execute commands with back ticks
If you need to include the output of a complex command in your script, you can write the statement inside back ticks.
Syntax:
var= `commands`
Example: Suppose we want to get the output of a list of mountpoints with tmpfs
in their name. We can craft a statement like this: df -h | grep tmpfs
.
To include it in the bash script, we can enclose it in back ticks.
#!/bin/bash
var=`df -h | grep tmpfs`
echo $var
How to get arguments for scripts from the command line
It is possible to give arguments to the script on execution.
$@
represents the position of the parameters, starting from one.
#!/bin/bash
for x in $@
do
echo "Entered arg is $x"
done
Run it like this:
./script arg1 arg2
How to Automate Scripts by Scheduling via cron Jobs
Cron is a job scheduling utility present in Unix like systems. You can schedule jobs to execute daily, weekly, monthly or in a specific time of the day. Automation in Linux heavily relies on cron jobs.
Below is the syntax to schedule crons:
# Cron job example
* * * * * sh /path/to/script.sh
Here, *
represent represents minute(s) hour(s) day(s) month(s) weekday(s), respectively.
Below are some examples of scheduling cron jobs.
SCHEDULE | SCHEDULED VALUE |
---|---|
5 0 * 8 * | At 00:05 in August. |
5 4 * * 6 | At 04:05 on Sunday. |
0 22 * * 1-5 | At 22:00 on every day-of-week from Monday through Friday. |