Learn Bash Quickly: Master Bash Scripting and Learn How To Automate Boring Linux Tasks
Learn Bash Quickly: Master Bash Scripting and Learn How To Automate Boring Linux Tasks
4. Adding Comments
-----------------------------------------
Create and Run your first Shell Script
-----------------------------------------
Convert your Shell script into a Bash Script
1. Insert the shebang line at the very beginning of your shell script:
#!/bin/bash
-----------------------------------------
Editing your PATH variable
export PATH:$PATH:/home/elliot/scripts
-----------------------------------------
Adding Comments
#!/bin/bash
# This is a comment
echo "Hello, Friend!" # This is a simple echo statement
Module 2
elliot@allsafe:~$ cat module2.title
************ Bash Variables ************
Module 2
elliot@allsafe:~$ cat module2.overview
-----------------------------------
1. Using variables in bash scripts
3. Constant Variables
4. Command Substitutions
read name
age=27
age=23
letter=‘c’
color=‘blue’
year=2022
Constant Variables
elliot@allsafe:~$ PI=123
bash: PI: readonly variable
elliot@allsafe:~$ TODAY=$(date)
elliot@allsafe:~$ echo $TODAY
Thu 17 Jun 2021 12:59:25 PM CST
elliot@allsafe:~$ TODAY=`date`
elliot@allsafe:~$ echo $date
Thu 17 Jun 2021 01:01:28 PM CST
variable=$(command)
variable=`command`
A Smarter “Hello, Friend!” Script
#!/bin/bash
#!/bin/bash
#!/bin/bash
#!/bin/bash
#!/bin/bash
file1="f1.txt"
file2="f2.txt"
file3="f3.txt"
file4="f4.txt"
file5="f5.txt"
#!/bin/bash
… now we need to access the array elements! We will see in the next slide
Accessing array elements
elliot@allsafe:~$ cat reverse.sh
#!/bin/bash
elliot@allsafe:~$ ./reverse.sh
f5.txt f4.txt f3.txt f2.txt f1.txt
Accessing array elements
--- Continued
elliot@allsafe:~$ echo ${files[*]}
elliot@allsafe:~$ files[0]="a.txt"
Adding array elements
#!/bin/bash
distros=("Ubuntu" "Red Hat" "Fedora")
echo ${distros[*]}
distros+=("Kali")
echo ${distros[*]}
elliot@allsafe:~$ ./distros.sh
Ubuntu Red Hat Fedora
Ubuntu Red Hat Fedora Kali
Deleting array elements
elliot@allsafe:~$ cat numbers.sh
#!/bin/bash
num=(1 2 3 4 5)
echo ${num[*]}
unset num[2]
echo ${num[*]}
unset num
echo ${num[*]}
elliot@allsafe:~$ ./numbers.sh
1 2 3 4 5
1 2 4 5
Creating hybrid arrays
elliot@allsafe:~$ cat user.sh
#!/bin/bash
total=$(($fs1 + $fs2))
$((arithmetic-expression))
$((10-3)) ==> 7
Multiplication and Division
GIGA=$1
MEGA=$(($GIGA * 1024))
elliot@allsafe:~$ ./giga2mega.sh 4
4 GB is equal to 4096 MB
Multiplication and Division
--- Continued
KILO=$(($GIGA * 1024 * 1024))
a=$1
b=$2
result=$(($a**$b))
echo="$a^$b=$result"
elliot@allsafe:~$ ./power.sh 2 3
2^3=8
elliot@allsafe:~$ ./power.sh 3 2
3^2=9
elliot@allsafe:~$ ./power.sh 5 2
5^2=25
Powers and Remainders
--- Continued
rem=$(( 17 % 5 ))
C=$1
F=$(echo "scale=2; $C * (9/5) + 32" | bc –l)
echo "$C degrees Celsius is equal to $F degrees Fahrenheit."
elliot@allsafe:~$ ./c2f.sh 2
2 degrees Celsius is equal to 35.60 degrees Fahrenheit.
elliot@allsafe:~$ ./c2f.sh -3
-3 degrees Celsius is equal to 26.60 degrees Fahrenheit.
elliot@allsafe:~$ ./c2f.sh 27
27 degrees Celsius is equal to 80.60 degrees Fahrenheit.
Module 6
elliot@allsafe:~$ cat module6.title
************* Bash Strings ***************
Module 6
elliot@allsafe:~$ cat module6.overview
-----------------------------------
1. Get String Length
2. Concatenating Strings
3. Finding Substrings
4. Extracting Substrings
5. Replacing Substrings
6. Deleting Substrings
elliot@allsafe:~$ distro="Ubuntu"
str1="Mr."
str2=" Robot"
str3=$str1$str2
echo $str3
elliot@allsafe:~$ ./con.sh
Mr. Robot
Finding Substrings
expr index string substr
elliot@allsafe:~$ word="Cool"
elliot@allsafe:~$ cell="112-358-1321"
elliot@allsafe:~$ echo ${cell/-}
112358-1321
elliot@allsafe:~$ cell=${cell//-}
Converting Uppercase
and Lowercase Letters
elliot@allsafe:~$ legend="john nash"
elliot@allsafe:~$ actor="JULIA ROBERTS"
root@allsafe:~# ./root.sh
You are root
Using if-else statement
elliot@allsafe:~$ cat root.sh
#!/bin/bash
root@allsafe:~# ./root.sh
You are root
elliot@allsafe:~$ ./root.sh
You are not root
Using elif statement
elliot@allsafe:~$ cat age.sh
#!/bin/bash
AGE=$1
elliot@allsafe:~$ ./age.sh 18
You are a teenager.
elliot@allsafe:~$ ./age.sh 44
You are an adult.
elliot@allsafe:~$ ./age.sh 70
You are an elder.
Using nested if statements
elliot@allsafe:~$ cat weather.sh
#!/bin/bash
TEMP=$1
elliot@allsafe:~$ ./weather.sh 8
The weather is cold.
elliot@allsafe:~$ ./weather.sh 16
The weather is nice.
elliot@allsafe:~$ ./weather.sh 30
The weather is hot.
case expression in
pattern1 )
Commands ;;
pattern2 )
Commands ;;
pattern3 )
Commands ;;
* )
Commands ;;
esac
Using case statement
… Continued
elliot@allsafe:~$ cat char.sh
#!/bin/bash
CHAR=$1
case $CHAR in
[a-z])
echo "Small Alphabet." ;;
[A-Z])
echo "Big Alphabet." ;;
[0-9])
echo "Number." ;;
*)
echo "Special Character." ;;
esac
Using case statement
… Continued
elliot@allsafe:~$ ./char.sh a
Small Alphabet.
elliot@allsafe:~$./char.sh Z
Big Alphabet.
elliot@allsafe:~$./char.sh 4
Number.
elliot@allsafe:~$./char.sh $
Special Character.
Test Conditions in Bash
Condition Meaning
$a -lt $b $a < $b
$a -gt $b $a > $b
$a -le $b $a <= $b
$a -ge $b $a >= $b
$a is equal to $b
$a -eq $b
$a == $b
$a is NOT equal to $b
$a -ne $b
$a != $b
-e $FILE $FILE exists
if [ $# -ne 1 ]; then
echo "Error: Invalid number of arguments."
exit 1
fi
file=$1
if [ -f $file ]; then
echo "$file is a regular file."
elif [ -L $file ]; then
echo "$file is a soft link."
elif [ -d $file ]; then
echo "$file is a directory."
else
echo "$file does not exist."
fi
Test Conditions in Bash
--- Continued
elliot@allsafe:~$ ./filetype.sh
Error: Invalid number of arguments.
elliot@allsafe:~$ ./for.sh
Hello, Friend 0!
Hello, Friend 1!
Hello, Friend 2!
Hello, Friend 3!
Hello, Friend 4!
Hello, Friend 5!
Hello, Friend 6!
Hello, Friend 7!
Hello, Friend 8!
Hello, Friend 9!
For Loops In Bash
** List/Range for loops**
for i in {0..9}; do
echo "Hello, Friend $i!"
done
For Loops In Bash
** List/Range for loops**
… Continued
5. Recursive Functions
-----------------------------------
Creating Functions
in Bash
elliot@allsafe:~$ cat fun.sh
#!/bin/bash
function_name () {
Commands hello () {
} echo "Hello, Friend!"
}
hello
hello
function function_name() { hello
Commands
} elliot@allsafe:~$ ./fun.sh
Hello, Friend!
Hello, Friend!
Hello, Friend!
Returning Function Values
elliot@allsafe:~$ cat error.sh
#!/bin/bash
error() {
blabla
return 0
}
error
echo "The exit status of the error function is: $?"
Returning Function Values
… Continued
elliot@allsafe:~$ ./error.sh
./error.sh: line 4: blabla: command not found
The exit status of the error function is: 0
Passing Function Arguments
elliot@allsafe:~$ cat iseven.sh elliot@allsafe:~$ ./iseven.sh
#!/bin/bash 3 is odd.
4 is even.
iseven () { 20 is even.
if [ $(( $1 % 2 )) -eq 0 ]; then 111 is odd.
echo "$1 is even."
else
echo "$1 is odd."
fi
}
iseven 3
iseven 4
iseven 20
iseven 111
Passing Function Arguments
… Continued
elliot@allsafe:~$ cat funarg.sh
#!/bin/bash
fun() {
echo "$1 is the first argument to fun()"
echo "$2 is the second argument to fun()"
}
fun Yes 7
Passing Function Arguments
… Continued
elliot@allsafe:~$ ./funarg.sh Cool Stuff
Cool is the first argument to the script.
Stuff is the second argument to the script.
Yes is the first argument to fun()
7 is the second argument to fun()
Local and Global Variables
v1='A'
v2='B'
myfun() {
local v1='C'
v2='D'
echo "Inside myfun(): v1: $v1, v2: $v2"
}
2. Automating Backups
servers=$(cat inventory.txt)
for i in $servers; do
echo $i
ssh $i "sudo useradd -m -u $uid $usrname"
if [ $? -eq 0 ]; then
echo "User $usrname is added successfully on $i"
else
echo "Error on $i"
fi
done
Automating User Management
… Continued
elliot@allsafe:~$ ./adduser.sh
Enter the username: ansible
Enter the user id: 777
webserver1
User ansible is added successfully on webserver1
webserver2
User ansible is added successfully on webserver2
webserver3
User ansible is added successfully on webserver3
webserver4
User ansible is added successfully on webserver4
webserver5
User ansible is added successfully on webserver5
Automating Backups
elliot@allsafe:~$ cat backup.sh #cleanup /tmp
#!/bin/bash sudo rm /tmp/*.gz
for i in "${backup_dirs[@]}"; do
sudo tar -Pczf /tmp/$i-$backup_date.tar.gz $i
if [ $? -eq 0 ]; then
echo "$i backup succeeded."
else
echo "$i backup failed."
fi
scp /tmp/$i-$backup_date.tar.gz $dest_server:$dest_dir
if [ $? -eq 0 ]; then
echo "$i backup transfer succeeded."
else
echo "$i backup transfer failed."
fi
done
Automating Backups
... Continued
elliot@allsafe:~$ ./backup.sh
Starting backup of: /etc /home /boot
/etc backup succeeded.
etc-Jun-20-21.tar.gz 100% 526KB 50.3MB/s 00:02
/etc backup transfer succeeded.
/home backup succeeded.
home-Jun-20-21.tar.gz 100% 5840 11.0MB/s 00:04
/home backup transfer succeeded.
/boot backup succeeded.
boot-Jun-20-21.tar.gz 100% 39MB 67.4MB/s 03:26
/boot backup transfer succeeded.
Backup script is done.
elliot@allsafe:~$ crontab –e
crontab: installing new crontab
elliot@allsafe:~$ crontab -l
0 0 * * * /home/elliot/scripts/backup.sh
Monitoring Disk Space
for i in ${filesystems[@]}; do
usage=$(df -h $i | tail -n 1 | awk '{print $5}' | cut -d % -f1)
if [ $usage -ge 90 ]; then
alert="Running out of space on $i, Usage is: $usage%"
echo "Sending out a disk space alert email."
echo $alert | mail -s "$i is $usage% full" [email protected]
fi
done
Bonus: Debugging your Bash
Scripts (ALL)
elliot@allsafe:~$ cat giga2mega.sh
#!/bin/bash -x
GIGA=$1
MEGA=$(( $GIGA * 1024))
GIGA=$1
set -x # activate debugging from here
MEGA=$(( $GIGA * 1024))
set +x # stop debugging from here
echo "$GIGA GB is equal to $MEGA MB“
elliot@allsafe:~$ giga2mega.sh 4
+ MEGA=4096
+ set +x
4 GB is equal to 4096 MB
Bonus: Running a Bash Script
from Another One!
elliot@allsafe:~$ cat first.sh
#!/bin/bash
echo "Running the first script ..." && sleep 1
second.sh