Bash Loops && Functions
For Loop
for var in item1 item2 ... itemN
do
command1
command2
....
...
commandN
done
for var in list-of-values
do
command1
command2
....
...
commandN
done
for var in $(Linux-command-name)
do
command1
command2
....
...
commandN
done
EX:
#!/bin/bash
for i in 1 2 3 4 5
do
echo "Welcome $i times."
done
#!/bin/bash
# A shell script to verify user password database
files="/etc/passwd /etc/group /etc/shadow /etc/gshdow"
for f in $files
do
[ -f $f ] && echo "$f file found" || echo "*** Error - $f file missing."
done
#!/bin/bash
# A simple shell script to display a file on screen passed as command line argument
[ $# -eq 0 ] && { echo "Usage: $0 file1 file2 fileN"; exit 1; }
# read all command line arguments via the for loop
for f in $*
do
echo
echo "< $f >"
[ -f $f ] && cat $f || echo "$f not file."
echo "------------------------------------------------"
done
#!/bin/bash
echo "Printing file names in /tmp directory:"
for f in $(ls /tmp/*)
do
echo $f
done
#!/bin/bash
n=$1
# make sure command line arguments are passed to the script
if [ $# -eq 0 ]
then
echo "A shell script to print multiplication table."
echo "Usage : $0 number"
exit 1
fi
# Use for loop
for i in {1..10}
do
echo "$n * $i = $(( $i * $n))"
done
#!/bin/bash
for ((i = 1; i <= 5; i++))
do
echo -n "$i "
done
Nested for loop statement
#!/bin/bash
# A shell script to print each number five times.
for (( i = 1; i <= 5; i++ )) ### Outer for loop ###
do
for (( j = 1 ; j <= 5; j++ )) ### Inner for loop ###
do
echo -n "$i "
done
echo "" #### print the new line ###
done
#!/bin/bash
for (( i = 1; i <= 8; i++ )) ### Outer for loop ###
do
for (( j = 1 ; j <= 8; j++ )) ### Inner for loop ###
do
total=$(( $i + $j)) # total
tmp=$(( $total % 2)) # modulus
# Find out odd and even number and change the color
# alternating colors using odd and even number logic
if [ $tmp -eq 0 ];
then
echo -e -n "\033[47m "
else
echo -e -n "\033[40m "
fi
done
echo "" #### print the new line ###
done
While loop
while [ condition ]
do
command1
command2
..
....
commandN
done
#!/bin/bash
# set n to 1
n=1
# continue until $n equals 5
while [ $n -le 5 ]
do
echo "Welcome $n times."
n=$(( n+1 )) # increments $n
done
Reading A Text File
#!/bin/bash
file=/etc/resolv.conf
while IFS= read -r line
do
# echo line is stored in $line
echo $line
done < "$file"
#!/bin/bash
file=/etc/resolv.conf
# set field separator to a single white space
while IFS=' ' read -r f1 f2
do
echo "field # 1 : $f1 ==> field #2 : $f2"
done < "$file"
#!/bin/bash
file=/etc/passwd
# set field delimiter to :
# read all 7 fields into 7 vars
while IFS=: read -r user enpass uid gid desc home shell
do
# only display if UID >= 500
[ $uid -ge 500 ] && echo "User $user ($uid) assigned \"$home\" home directory with $shell shell."
done < "$file"
Infinite while loop
- true command - do nothing, successfully (always returns exit code 0)
- false command - do nothing, unsuccessfully (always returns exit code 1)
- : command - no effect; the command does nothing (always returns exit code 0)
#!/bin/bash
# Recommend syntax for setting an infinite while loop
while :
do
echo "Do something; hit [CTRL+C] to stop!"
done
#!/bin/bash
while true
do
echo "Do something; hit [CTRL+C] to stop!"
done
#!/bin/bash
while false
do
echo "Do something; hit [CTRL+C] to stop!"
done
#!/bin/bash
# set an infinite loop
while :
do
clear
# display menu
echo "Server Name - $(hostname)"
echo "-------------------------------"
echo " M A I N - M E N U"
echo "-------------------------------"
echo "1. Display date and time."
echo "2. Display what users are doing."
echo "3. Display network connections."
echo "4. Exit"
# get input from the user
read -p "Enter your choice [ 1 -4 ] " choice
# make decision using case..in..esac
case $choice in
1)
echo "Today is $(date)"
read -p "Press [Enter] key to continue..." readEnterKey
;;
2)
w
read -p "Press [Enter] key to continue..." readEnterKey
;;
3)
netstat -nat
read -p "Press [Enter] key to continue..." readEnterKey
;;
4)
echo "Bye!"
exit 0
;;
*)
echo "Error: Invalid option..."
read -p "Press [Enter] key to continue..." readEnterKey
;;
esac
done
Until loop
#!/bin/bash
i=1
until [ $i -gt 6 ]
do
echo "Welcome $i times."
i=$(( i+1 ))
done
Select loop
#!/bin/bash
# Set PS3 prompt
PS3="Enter the space shuttle to get more information: "
# Set shuttle list
select shuttle in columbia endeavour challenger discovery atlantis enterprise exit
do
echo "$shuttle selected"
if [ "$shuttle" == "exit" ]
then
echo "Exiting..."
break
fi
done
1) columbia 3) challenger 5) atlantis 7) exit
2) endeavour 4) discovery 6) enterprise
Enter the space shuttle to get more information: 5
atlantis selected
Enter the space shuttle to get more information: 7
exit selected
Exiting...
break & continue
break
break N # break N times, ex: exit for and then exit while
continue
continue N # ~ break N
challenges
Create a menu-driven script using the select statement to display calorie information for food items such as pizza, burger, salad, and pasta
#!/bin/bash
PS3="Choose an option to view its calorie content: "
food_items="Pizza Burger Salad Pasta Quit"
select choice in $food_items
do
case $choice in
"Pizza")
echo "Calories in Pizza: 100";;
"Burger")
echo "Calories in Burger: 100";;
"Salad")
echo "Calories in Salad: 100";;
"Pasta")
echo "Calories in Pasta: 100";;
"Quit")
echo "Exiting the program. Goodbye!"
break;;
*)
echo "Invalid choice. Please select a valid option.";;
esac
done
Write a shell script that, given a file name as the argument will count vowels, blank spaces, characters, number of line and symbols
#!/bin/bash
file=$1
count=0
[ $# -ne 1 ] && { echo "Give me a file name as the first argument, please!"; exit 1; }
[ ! -f $file ] && { echo "$file is not a file"; exit 1; }
while read -n 1 c; do
l=$(echo $c | tr [:upper:] [:lower:])
[[ $l == "a" || $l == "e" || $l == "i" || $l == "o" || $l == "u" ]] && ((count++))
done < "$file"
echo "Number of Vowels: $count"
echo "Number of characters: $(cat "$file" | wc -m)"
echo "Number of lines: $(cat "$file" | wc -l)"
echo "Blank lines: $(grep -c '^$' "$file")"
exit 0
./bash8.sh a.tx
a.tx is not a file
./bash8.sh
Give me a file name as the first argument, please!
./bash8.sh a.txt
Number of Vowels: 8
Number of characters: 32
Number of lines: 4
Blank lines: 1
Functions
Defining & Writing & Calling function
function funct_name(){
....
}
funct_name(){
.....
}
funct_name # call
local variable
#!/bin/bash
create_jail(){
d=$1
echo "create_jail(): d is set to $d"
}
d=/apache.jail
echo "Before calling create_jail d is set to $d"
create_jail "/home/apache/jail"
echo "After calling create_jail d is set to $d"
# Before calling create_jail d is set to /apache.jail
# create_jail(): d is set to /home/apache/jail
# After calling create_jail d is set to /home/apache/jail
#!/bin/bash
# global d variable
d=/apache.jail
# User defined function
create_jail(){
# d is only visible to this fucntion
local d=$1
echo "create_jail(): d is set to $d"
}
echo "Before calling create_jail d is set to $d"
create_jail "/home/apache/jail"
echo "After calling create_jail d is set to $d"
# Before calling create_jail d is set to /apache.jail
# create_jail(): d is set to /home/apache/jail
# After calling create_jail d is set to /apache.jail
Returning from a function
#!/bin/bash
# Variables
domain="CyberCiti.BIz HUYNA"
out=""
##################################################################
# Purpose: Converts a string to lower case
# Arguments:
# $@ -> String to convert to lower case
##################################################################
function to_lower()
{
echo $2
local str="$@"
local output
output=$(tr '[A-Z]' '[a-z]'<<<"${str}")
echo $output
}
# invoke the to_lower()
to_lower "This Is a TEST"
# invoke to_lower() and store its result to $out variable
out=$(to_lower ${domain})
# Display back the result from $out
echo "Domain name : $out"
Shell functions library
1 file chứa các list functs => library funct. Sẽ được import vào script khác và dùng như python import thư viện:
#!/bin/bash
# set variables
declare -r TRUE=0
declare -r FALSE=1
declare -r PASSWD_FILE=/etc/passwd
##################################################################
# Purpose: Converts a string to lower case
# Arguments:
# $1 -> String to convert to lower case
##################################################################
function to_lower()
{
local str="$@"
local output
output=$(tr '[A-Z]' '[a-z]'<<<"${str}")
echo $output
}
##################################################################
# Purpose: Display an error message and die
# Arguments:
# $1 -> Message
# $2 -> Exit status (optional)
##################################################################
function die()
{
local m="$1" # message
local e=${2-1} # default exit status 1
echo "$m"
exit $e
}
##################################################################
# Purpose: Return true if script is executed by the root user
# Arguments: none
# Return: True or False
##################################################################
function is_root()
{
[ $(id -u) -eq 0 ] && return $TRUE || return $FALSE
}
##################################################################
# Purpose: Return true $user exits in /etc/passwd
# Arguments: $1 (username) -> Username to check in /etc/passwd
# Return: True or False
##################################################################
function is_user_exits()
{
local u="$1"
grep -q "^${u}" $PASSWD_FILE && return $TRUE || return $FALSE
}
#!/bin/bash
# Load the myfunctions.sh
# My local path is /home/vivek/lsst2/myfunctions.sh
. /home/vivek/lsst2/myfunctions.sh
# Define local variables
# var1 is not visitable or used by myfunctions.sh
var1="The Mahabharata is the longest and, arguably, one of the greatest epic poems in any language."
# Invoke the is_root()
is_root && echo "You are logged in as root." || echo "You are not logged in as root."
# Find out if user account vivek exits or not
is_user_exits "vivek" && echo "Account found." || echo "Account not found."
# Display $var1
echo -e "*** Orignal quote: \n${var1}"
# Invoke the to_lower()
# Pass $var1 as arg to to_lower()
# Use command substitution inside echo
echo -e "*** Lowercase version: \n$(to_lower ${var1})"
load lib funct to current shell environment:
. myfunctions.sh
. /path/to/myfunctions.sh
source myfunctions.sh
source /path/to/myfunctions.sh
# dot is an alias of source command
Recursive function
#!/bin/bash
# fact.sh - Shell script to to find factorial of given command line arg
factorial(){
local i=$1
local f
declare -i i
declare -i f
# factorial() is called until the value of $f is returned and is it is <= 2
# This is called the recursion
[ $i -le 2 ] && echo $i || { f=$(( $(factorial $((i-1)) ) * i )); echo $f; }
}
# display usage
[ $# -eq 0 ] && { echo "Usage: $0 number"; exit 1; }
# call factorial
factorial $1
Putting functions in background
name(){
echo "Do something"
sleep 1
}
# put a function in the background
name &
# do something
Challenge
Create user-defined functions in a shell script for the following tasks:
- add_user() - Add a user to the system.
- add_group() - Add a group to the system.
- change_password() - Change user password.
- delete_user() - Remove a user from the system.
#!/bin/bash
# cut -d: -f1 /etc/group | sort | uniq
# cut -d: -f1 /etc/passwd
# Check if the script is run as root
[ "$EUID" -ne 0 ] && { echo "This script requires root privileges. Please run it with sudo."; exit 1; }
PS3="Give me your choice: "
choices=("add_user" "add_group" "change_password" "delete_user" "delete_group" "Quit")
select choice in "${choices[@]}"
do
case $choice in
"add_user")
read -p "Give me the username to add: " username
useradd "$username"
passwd "$username"
echo "Added $username!"
;;
"add_group")
read -p "Give me the group name to add: " groupname
groupadd "$groupname"
;;
"change_password")
read -p "Give me the username to change the password: " username
passwd "$username"
;;
"delete_user")
read -p "Give me the username to delete: " username
userdel "$username"
;;
"delete_group")
read -p "Give me the group name to delete: " groupname
groupdel "$groupname"
;;
"Quit")
echo "You chose to quit!"
break
;;
*)
echo "Invalid choice. Please select a valid option."
;;
esac
done