Table of Contents
- Introduction
- What is a Shebang or hashbang (#! )
- How to create a basic bash script
- How to use Special Characters in Bash Scripts
- How to Deal with the arguments in bash scripts
Introduction
Wondering how to do the bash scripting for automating your day to day tasks? We got you covered through this series of training on bash scripting.
In this article we will be going through some fundamentals to know before getting into advanced bash scripting
What is a Shebang or hashbang (#! )
Shebang or hashbang #! present on the head of the script tells which interpreter to be used. Here are some examples hashbangs you will see in bash scripts
#!/bin/bash - denotes using Bash shell ( Bourne Again SHell) as interpreter
#!/bin/sh - denotes using Bourne shell
Please note that bash and sh are different shells . Typically we can call Bash is a shell with more features than the sh shell
If we are willing to use python as interpreter , we can do the following
For python3
#!/usr/bin/env python3
For python 2
#!/usr/bin/env python2
Following to be used only when the script you are writing is compatible for both python 2.x and python 3.x
#!/usr/bin/env python
Do not use the following as we may see some differences in the location of the python install
#!/bin/python
Or
#!/usr/local/bin/python
Here are few other examples on the Hashbang to use other interpreters
For perl scripts
#!/usr/bin/env perl
For ruby scripts
#!/usr/bin/env ruby
For sed and awk scripts you can use the following hashbangs
#!/usr/bin/sed -f
#!/usr/bin/awk -f
How to create a basic bash script
Now let’s dive into creating the bash script file and executing it
Here is a example of a basic bash script where we are using the well known echo command to print a text “this is a bash script“
[root@discoveringsystems Bash-Scripting]# cat bash_script
#!/bin/bash
echo " this is a bash script "
Currently we can see that the bash_script file doesn’t have execute permission
[root@discoveringsystems Bash-Scripting]# ls -l bash_script
-rw-r--r--. 1 root root 45 Jan 20 11:42 bash_script
So we get the following error when trying to execute it by using the shebang to automatically assign the interpreter as bash
[root@discoveringsystems Bash-Scripting]# ./bash_script
bash: ./bash_script: Permission denied
Then we changed the file permission to make it a executable file for bash
[root@discoveringsystems Bash-Scripting]# chmod 744 bash_script
[root@discoveringsystems Bash-Scripting]# ls -l bash_script
-rwxr--r--. 1 root root 45 Jan 20 11:42 bash_script
After providing the permission this worked now
[root@discoveringsystems Bash-Scripting]# cat bash_script
#!/bin/bash
echo " this is a bash script "
[root@discoveringsystems Bash-Scripting]# ./bash_script
this is a bash script
How to use Special Characters in Bash Scripts
In this section we will be covering some special characters used in the bash scripts to make things easier for you to get used to writing bash scripts
Comment (#)
Comments will not be executed as part of the script. However they are helpful to write some notes on the function of a particular block of the script. Here are some examples to comment on the script
[root@discoveringsystems Bash-Scripting]# cat bash_script
#!/bin/bash
#first comment
#second comment
echo " this is a bash script " # 3rd comment
While executing we were able to see that the comments were ignored. Also note the different places we can comment on a script , I have commented in a way that covers some of the possible places to comment on the script.
[root@discoveringsystems Bash-Scripting]# ./bash_script
this is a bash script
Command separator (;)
It helps adding two or more commands on the same line. For example,
[root@discoveringsystems Bash-Scripting]# cat bash_script
#!/bin/bash
echo "one" ; echo "two" ; echo "three"
[root@discoveringsystems Bash-Scripting]# ./bash_script
one
two
three
Dollar sign for Variable substitution ($)
We can use the dollar sign ($) for variable substitution in bash scripts . For example,
[root@discoveringsystems Bash-Scripting]# cat bash_script
#!/bin/bash
var_name="one"
echo "$var_name"
[root@discoveringsystems Bash-Scripting]# ./bash_script
one
Escape character ( \)
Using the escape character we can skip processing of other bash special characters. For example , in the below example scripts , the Dollar sign was used to call the defined variables, However I used the “\” to escape treating it as the bash special character and we can see that the variable is not called.
#without using the escape character
[root@discoveringsystems Bash-Scripting]# cat bash_script
#!/bin/bash
var_name="one"
echo "$var_name" ; echo "two" ; echo "three"
[root@discoveringsystems Bash-Scripting]# ./bash_script
one
two
three
# using the escape character in this script
[root@discoveringsystems Bash-Scripting]# cat bash_script
#!/bin/bash
var_name="one"
echo "\$var_name" ; echo "two" ; echo "three"
[root@discoveringsystems Bash-Scripting]# ./bash_script
$var_name
two
three
Single Quotes (‘ ’) and Double Quotes (“ “)
Using the single quotes we can preserve bash special characters within the quotes ,that means it can literally be interpreted as the strings. Double Quotes can be used for the strings which contain spaces and some special characters used within the double quotes are processed by the bash. Here is the example for using both singles quotes and double quotes within bash script
[root@discoveringsystems Bash-Scripting]# cat bash_script
#!/bin/bash
var_name="one"
echo '$var_name' ; echo "$var_name and two and three"
[root@discoveringsystems Bash-Scripting]# ./bash_script
$var_name
one and two and three
Arithmetic expansion (( ))
This is used within the scripts to deal with expressions and calculations. Here is the example for arithmetic expansion use in the bash scripts
[root@discoveringsystems Bash-Scripting]# cat variable_test.sh
#!/bin/bash
Number=1
value=$((Number+Number))
echo $value
[root@discoveringsystems Bash-Scripting]# sh variable_test.sh
2
Redirections
Stdout is file descriptor 1 and the stderr is file descriptor 2. Using redirections, we can redirect these streams to a file instead of getting printed on the terminal
>
Redirects the stdout to a file , if that file is not present it creates a file. If the file is present it just overwrites the contents of the output to the file . Using “>” is same as using the “1>” as it redirects the stdout( file descriptor 1)
[root@discoveringsystems Bash-Scripting]# echo "this is a redirection file" > redirection_file
[root@discoveringsystems Bash-Scripting]# cat redirection_file
this is a redirection file
[root@discoveringsystems Bash-Scripting]# echo "this is an overwrite example" > redirection_file
[root@discoveringsystems Bash-Scripting]# cat redirection_file
this is an overwrite example
>>
This only appends the output to the file , doesn’t do the overwrite. In the following example we are going to append some text to the file
[root@discoveringsystems Bash-Scripting]# cat redirection_file
this is an overwrite example
[root@discoveringsystems Bash-Scripting]# echo "this is an append example" >> redirection_file
[root@discoveringsystems Bash-Scripting]# cat redirection_file
this is an overwrite example
this is an append example
&> and &>>
This redirects both the stdout and the stderr of the command to the file . You can use both the redirects with either overwrite (&>) or redirect with append (&>>)
Here is an example to understand the &> and &>>. I am going to use the sleep command to explain both the stdout and stderr redirection
# The command errored out so it prints stderr
[root@discoveringsystems Bash-Scripting]# sleep
sleep: missing operand
Try 'sleep --help' for more information.
#The command worked this time so stdout is displayed , for working Sleep command the stdout is null
[root@discoveringsystems Bash-Scripting]# sleep 1
[root@discoveringsystems Bash-Scripting]#
# Command failed and the stderr is redirected to a file
[root@discoveringsystems Bash-Scripting]# sleep &> redirect_file
[root@discoveringsystems Bash-Scripting]# cat redirect_file
sleep: missing operand
Try 'sleep --help' for more information.
# command worked and the stdout is redirected to a file
[root@discoveringsystems Bash-Scripting]# sleep 1 &> redirect_file
[root@discoveringsystems Bash-Scripting]# cat redirect_file
[root@discoveringsystems Bash-Scripting]#
Similarly we can also do the append
[root@discoveringsystems Bash-Scripting]# sleep &>> redirect_file
[root@discoveringsystems Bash-Scripting]# cat redirect_file
sleep: missing operand
Try 'sleep --help' for more information.
[root@discoveringsystems Bash-Scripting]# sleep 1 &>> redirect_file
[root@discoveringsystems Bash-Scripting]# cat redirect_file
sleep: missing operand
Try 'sleep --help' for more information.
2>&1
This is used to redirect the stderr to stdout . Here in this example , we know that date “test”
will error out , so we are redirecting the stderr to stdout and then redirecting the stdout to a file.
[root@discoveringsystems Bash-Scripting]# date "test" 1> redirect_file 2>&1
[root@discoveringsystems Bash-Scripting]# cat redirect_file
date: invalid date ‘test’
1>&2
This is used to redirect the stdout to stderr . Here in this example , we know that the working “date”
command will print stdout , so we are redirecting the stdout to stderr and then redirecting the stderr to a file.
[root@discoveringsystems Bash-Scripting]# date 2> redirect_file 1>&2
[root@discoveringsystems Bash-Scripting]# cat redirect_file
Wed Jan 25 10:43:53 EST 2023
| Pipe
This passes the stdout of one command to the stdin of the next command. For example we can see that the stdout from the ls -l is piped to the grep command as the stdin so that it can produce filtered stdout as a result and print on the terminal
[root@discoveringsystems Bash-Scripting]# ls -l | grep -i bash
-rwxr--r--. 1 root root 85 Jan 23 10:39 bash_script
&
It is used to run a command or script as a background process. In this example we were running tail forever for the /dev/null file and made it to run in the background
[root@discoveringsystems Bash-Scripting]# tail -f /dev/null &
[1] 97904
[root@discoveringsystems Bash-Scripting]# jobs
[1]+ Running tail -f /dev/null &
We can bring that process to foreground using the “fg <job number from jobs output> “
. I killed the process after bringing it to the foreground
[root@discoveringsystems Bash-Scripting]# fg 1
tail -f /dev/null
^C
[root@discoveringsystems Bash-Scripting]# jobs
[root@discoveringsystems Bash-Scripting]#
$?
This is used to get the exit value of the previous command
In the following example , the date command errored out , when checking the exit value we found it to be 1 which means unsuccessful
[root@discoveringsystems Bash-Scripting]# date "test"
date: invalid date ‘test’
[root@discoveringsystems Bash-Scripting]# echo $?
1
In this example , the date command worked , when checking the exit value we found it to be 0 which means successful
[root@discoveringsystems Bash-Scripting]# date
Wed Jan 25 11:03:16 EST 2023
[root@discoveringsystems Bash-Scripting]# echo $?
0
Exit status in the Bash is an integer and You can see non-zero exit status ranges ( 1-255 ) , which indicates a failure . By using this exit status as conditionals ( if ) in the scripts we can validate a command working while running scripts and based on that do further processing
How to Deal with the arguments in bash scripts
Bash has some inbuilt variables to deal with the argument provided along with the script. Through the example script , let me explain the different things we can do with those.
$# helps getting the total number arguments provided along with the script
$@ helps getting all the variables passed along with the script as an array
$* helps getting all the variables passed along with the script as a single string
$1 helps to use the first argument passed with the script
$2 helps to use the second argument passed with the script
Likewise we can do $3 or more if we have many arguments passed with the script
[root@discoveringsystems Bash-Scripting]# cat bash_script
#!/bin/bash
echo "first argument is $1"
echo "second argument is $2"
echo "total number of arguments is $#"
echo "here is the actual arguments passed while running the script as an array : $@"
echo "here is the actual arguments passed while running the script as a single string : $*"
[root@discoveringsystems Bash-Scripting]# ./bash_script one two
first argument is one
second argument is two
total number of arguments is 2
here is the actual arguments passed while running the script as an array : one two
here is the actual arguments passed while running the script as a single string : one two