[Unix-Linux] Shell Scripting - If & Case & Loop & Function

Date:     Updated:

Categories:

Tags:

📋 This is my note-taking from what I learned in the Unix/Linux course!


If Statement

The syntax of the if statement is:

if conditional_expression
then
 «statements»
fi

Unlike python and similar to most other language, indentation is not necessary, however it does make it easier to see structure in your code.


Old vs New Syntax

  • New syntax use double brackets e.g. [[ ]] or (( ))
  • Old syntax use single bracket e.g. [ ]
  • I feel that the newer syntax will be easier to understand because of our past programming experiences.
  • So we will only use the new double brackets syntax.
  • The relational operators (==, !=, <, <=, >, >=) works as expected.


If Statement Using String

#simple 'if statement' using sting

if [["$1" == "hello"]]    #we are using string hence [[]]
then
  echo "This first argument is 'hello'"
else
  echo "This first argument was not 'hello'--"
  echo "It was $1."
fi


If Statement Using Numbers

#simple 'if statement' using numbers

if (("$1"%2 == 1))    #we are using number hence (())
then
  echo "$1 is an odd number"
else
  echo "$1 is an even number"
fi


Nested If Statement

#a nested 'if statement'

if (("$1" > 100))   #we are using number hence (())
then
  echo "$1 is a large number"
  if (("$1"%2 == 0))    #start of inner if
  then
    echo "$1 is also even"
  fi    #end of inner if
else    #else block of outer if
  echo "$1 is a small number"
fi    #end of outer if


More Complex Logic

We can use the Boolean operators || and && to create more complex logical conditions:

if [["$1" == 'hello']] || [["$1" == 'world']]
then
  echo "The first argument was '$1'"
fi

if [["$1" == 'hello']] && [["$2" == 'world']]
then
  echo "The first argument was '$1' and the second argument was '$2'"
fi


Operators When Working with Files

Operator Description
-f Checks if the path is a regular file
-d Checks if the path is a directory
-h Checks if the path is a symbolic link
-b Checks if the path is a block device
-c Checks if the path is a character device
-p Checks if the path is a named pipe (FIFO)
-S Checks if the path is a socket
-s Checks if the file exists and has a non-zero size
-e Checks if the path exists, regardless of the type
#!/bin/bash

# Author: Narendra
#   Name: shell03e.sh
#   Date: April 17, 2023
# Purpose: To demonstrate File Type Operators
#   1) -f -> Regular file
#   2) -d -> Directory
#   3) -h -> Symbolic link
#   4) -b -> Block device
#   5) -c -> Character device
#   6) -p -> Named pipe
#   7) -S -> Socket
#   8) -s -> non-empty file
#   9) -e -> file exist

var1='file1.txt'
var2='folder1'
var3='shortcut.lnk'

rm -i $var1   #erase the file if it exist
#-i prompts for confirmation before deleting the file represented by $var1
rm -ir $var2   #erase the file if it exist
#-ir prompts for confirmation and recursively deletes the directory represented by $var2 along with its contents

#create the file
touch $var1

#check if the file exist
if [[ -e "$var1" ]]
then
  echo "'$var1' does exist"
else
  echo "'$var1' does not exist"
fi

#check if it is regular file
if [[ -f "$var1" ]]
then
  echo "'$var1' is a regular file"
fi

#check if the file exist and has non-zero size
if [[ -s "$var1" ]]
then
  echo "'$var1' is not empty"
else
  echo "'$var1' is empty"
fi

#write something to the file
echo "Hello World" > $var1
if [[ -s "$var1" ]]
then
  echo "'$var1' is not empty"
else
  echo "'$var1' is empty"
fi

#create a directory
mkdir $var2
if [[ -d "$var2" ]]
then
  echo "'$var2' is a directory"
fi

#create a link
ln -s $var1 $var2/$var3
#`ln` creates links, `-s` specifies that we wanna create a link, `$var1` is the source file or directory that we wanna create a link to, `$var2/$var3` is the destination path where we wanna create the link -> $var2 is directory path and $var3 is the name of the link
if [[ -h "$var2/var3" ]]
then
  echo "'$var2/$var3' is a link"
fi


Case Statement

  • Both the case and the if statements serves the same purpose.
  • If your solution is a simple comparison, then you are better off using an if statement.
  • The case statement is inherently more readably.
  • Very easy to match patterns against a variable.
    You may use regular-expression and wildcard characters to define patterns.

The syntax of the case statement is:

case expression in
  pattern1)
    statement1
    ;;
  pattern2)
    statement1
    ;;
  pattern3)
    statement1
    ;;
esac


Case Statement

case $1 in
  bye)
    echo Fine,bye #Fine,bye and "Fine,bye" will produce the same result
    ;;
  hi|hello)
    echo Nice to see ya
    ;;
  what*)
    echo Fine, bye
    ;;
  *)    #default case
    echo 'Huh!'
    ;;
esac
read -p "Enter a command (start, stop, restart): " command

case $command in
  start)
    echo 'Starting the service...'
    ;;
  stop)
    echo 'Stopping the service...'
    ;;
  restart)
    echo 'Restarting the service...'
    ;;
  *)
    echo 'Invalid command'
    ;;
esac


Case Statement and If Statement

Case Statement:

case $fruit in
  apple)
    echo "It's an apple"
    ;;
  orange)
    echo "It's an orange"
    ;;
  banana)
    echo "It's a banana"
    ;;
  *)
    echo "Unknown fruit"
    ;;
esac

If Statement:

if [[$fruit == "apple"]]
then
  echo "It's an apple"
elif [[$fruit == "orange"]]
then
  echo "It's an orange"
elif [[$fruit == "banana"]]
then
  echo "It's a banana"
else
  echo "Unknown fruit"
fi


Loops

  • Each and every loop must:
    • First, the variable used in loop condition must be initialized, then execution of the loop begins.
    • A test (condition) is made at the beginning of each iteration.
    • The body of loop ends with a statement that modifies the value of the test (condition) variable.
    • Repeatedly execute a block of statements.
  • There are three loops:
    • for loop
    • while loop
    • until loop

The syntax of the for loop is:

for var in item1 item2 ... itemN
do
  statement1
  statement2
  statement3
done


For Loop

for num in 1 2 3 4 5
do
  echo $num
done
for var in a b c d
do
  echo $var
done


For Loop Using a Range

for var in item[246]
do
  echo -n $var
done

#Output: item2 item4 item6
for var in item{1...5}
do
  echo -n $var
done

#Output: item1 item2 item3 item4 item5
output='code.txt'
rm -i $output #what does '-i' do? Asking permission

files='ls * .sh'

for file in $files
do
	echo'================' >> $output
	echo $file >> $output
	echo'================' >> $output
	cat -n $file >> $output #"-n" is number of line
	echo >> $output
	echo >> $output
	echo >> $output
done

Output:

chmod 744 week05d.sh
/.week05d.sh
#print
#shell01a.sh
#shell01b.sh
#shell01c.sh
#shell01d.sh
# .....
./week05d.sh
cat code.txt
#print
#================
#shell01a.sh
#================
#content of file(3 echos)

#================
#shell01b.sh
#================
#content of file(3 echos)

#shell01c.sh
#shell01d.sh
# .....
#week05d.sh


For Loop Using List

for var in list_of_values
do
  statement1
  statement2
  statement3
done
values=(a b c d)

for var in ${values[@]}
do
  echo $var
done


Until and While Loop

While loop:

while <<condition>>
do
  statement...
done
count=1

while (( $count <= 5 ))
do
  echo "Count: $count"
  (( count++ ))
done
  • The body is processed while the condition is true.
  • Prefer this to the until loop.

Until loop:

until <<condition>>
do
  statement...
done
  • The body is processed while the condition is true.
  • Advise against using this loop.


Functions

  • Function definitions in shell scripting is similar to method definition in c#. However, you don’t have to specify formal parameters.
    • Just use the variables $1, $2 etc. in your function
  • You may return a value from a function.
    • You have to access the shell variable $? To obtain the value.
  • You may also fake a return value by echo’ing a value and capturing the output of a function in a variable.
  • You may use global as well as local variables.
hello1()
{
  echo "Hello World"
}

hello2()
{
  echo "Hello World from $1"
}

hello3()
{
  local sum=`expr $1 + $2`
  echo "$sum"
}

hello1
hello2 Narendra
sum=`hello3 5 10`
echo "faking a return value: $sum"
sum=10

hello4()
{
  echo -n "Returning the sum of $1 and $2 which is"
  return `expr $1 + $2`
}

hello5()
{
  echo "****in function - Global variable sum: $sum"
  local a=`expr $sum + 123`
  echo "****in function - Local variable a: $a"
  b=`expr $sum + 321`
  echo "****in function - Global variable b: $b"
  sum=`expr $sum - 4`
  echo "****in function - Global variable sum: $sum"
}

hello4 15 7
echo "$?"
hello5
echo "Global variable sum: $sum"
echo "Local variable a: $a"
echo "Global variable b: $b"

In Unix/Linux shell scripts, $? is a special variable that holds the exit status of the last command executed. It is a way to check whether the command executed successfully or encountered an error.

For example, let’s say we have a command hello4 that we execute. After executing it, the exit status of the command will be stored in $?. If the command executed successfully, the exit status will be 0, indicating success. If there was an error or the command failed, the exit status will be a non-zero value.




Back to Top

See other articles in Category Unix-Linux

Leave a comment