Toggle Menu

Bash Scripts


Bash Scripts

Benefits:
  • Automate tasks
  • Simple commands
  • Users are given a controlled interface
  • Combination of utilities to form new commands
  • Quick protoyping of functionalities wthout compiling codes
#!/bin/bash specifies the path of the interpreter. Bash scripts are saved with a ".sh" (shell) extension
chmod u+x [fileName].sh makes files executable

Interactive script

e.g. Write a script that will read your name and student id and display to output
#!/bin/bash
echo "What is your name?"
read name
echo "Enter your student ID"
read id
echo your name is $name and your id is $id
Exit: set return value
$?: view return value of most recent command
\: indicates continuation in the next line/split line into multiple lines
;: separates commands
&&: aborts subsequent commands if one fails
||: proceeds until success
$0: script name
$1, $2 ...: First, Second, ... Parameters
$*: all parameters
$#: number of parameters

Command Substitution

- store result of a command
- Enclose inner command with backticks `` or enclose with $()
- innermost command is executed first and its standard output is inserted where substitution is done
- $() allows nesting
- expr: evaluate an expression
  • arithmetics
  • comparison
  • logical
  • $(()) or $(expr ...)
  • e.g. Add two inputs and print both summation
    #!/bin/bash
    result=$(expr $1 + $2)
    echo $1 + $2 = $result

Functions

  • execute procedures by building code blocks that implements a set of operations
  • function_name(){} or function function_name{}
  • to read arguments from function, use $1, $2
#!/bin/bash
sum() {
  echo "$1 + $2 = $(($1 + $2))"
}
sum 1 2
Single Quotation vs Double Quotation
  • echo "$HOME" -> /home/rcykoh
  • echo '$HOME' -> $HOME

If Statements

if [ condition ]
then
  statements
elif [ condition ]
then
  statements
else
  statements
fi
The following flags can be put inside the condition:
  • File Testing
    • -f check if regular file exists
    • -e check if file exists
    • -d check if directory
    • -r -w -x check if readable, writable, executable
  • Number Testing
    • -eq -ne check if equal, not equal
    • -gt -lt -ge -le check if greater, less, greater or equal, less or equal
  • Regex Testing - $var =~ <regex statement>
e.g. Read the total points the student collected and display 'Pass' if grade >= 50 and "Fail" if grade < 50
#!/bin/bash
echo "What is your grade?"
read grade
if [ grade -ge 50 ]; then
  echo "Pass"
else
  echo "Fail"
fi

Boolean Expressions

  • && and
  • || or
  • ! not
  • == checks if two strings are equal
e.g. Write a function that takes 3 inputs from user. First argument is add or subtract, the other are numbers to add/subtract. Write a program that implements the addition/subtraction.
#!/bin/bash
add(){
  result=$(($1 + $2))
}
subtract(){
  result=$(($1 - $2))
}
if [ "$#" -ne 3 ] || !( [ "$1" == 'add' ] || [ "$1" == 'sub' ]); then
  echo "Please input 3 arguments: (add or subtract), number1, number2"
  exit 1
else
  $1 $2 $3
fi
echo result is $result
Things to note:
  • There has to be a space between each square bracket as the square bracket is itself a command.
  • Variables should have double quotes "" around it to prevent bash from splitting it into separate words wherever there is an IFS (Internal Field Separator) variable, or whitespace characters (i.e. space, tab, newline). The variable would be interpreted as a glob (wildcard pattern).
  • One way to prevent this is through the use of double square brackets [[ ]]. This doesn't perform word splitting and pathname expansions, so double quoting is not necessary.

Case Statements

Case statements are used to compare a variable against different values.
case  $var  in
    pattern1|pattern2|pattern3)
        command1
        ;;
    pattern4|pattern5|pattern6)
        command2
        ;;
    pattern7|pattern8|patternN)
        command3
        ;;
    *)
        defaultcommand
        ;;
esac 
  • compares var against patterns until a match is founds
  • *) acts as a default and is executed if no match is found.
  • pattern can include wildcards
  • Must include:
    1. ;; at the end of each block
    2. esac at the end of case statement

String Manipulation

  • ${#string} return the length of string
  • ${string:s:n} return substring from start s for length n
  • ${string#*.} extract characters after dot .
  • ${string%txt} extract string before txt

Loops

For Loops

for var in list
do
  commands
done
e.g. Search for c files in the system, create dir CFolder, move the files to that dir, create a header file for each c file
#!/bin/bash
mkdir CFolder
for filename in *.c
do
  mv $filename CFolder
  touch CFolder/${filename%.c}.h
done
e.g. Write a shell that reads a filename and returns how many distinct words exists
#!/bin/bash
for word in $(cat $1); do
  echo $word >> tmp
done
distinctwords = $(sort tmp | uniq | wc -l)
echo "The total number of distinct words is $distinctwords"
e.g. Count the number of articles in file (a, the, The)
#!/bin/bash
articleCount=0
for word in $(cat $1); do
  if [[ $word =~ ^[T|t]he$ || $word == 'a' ]]
    then articleCount=$((articleCount + 1))
  fi
done
echo $articleCount

While Loops

Similar to a for loop that executes while provided conditional is true.
#!/bin/bash
num=$1
fact=1
while [[ $num -gt 0 ]]; do
  fact=$((fact * num))
  num=$((num - 1))
done
echo fact

Until Loops

Opposite of a while loop. It executes until provided conditional is true.
#!/bin/bash
num=$1
fact=1
until [[ $num -le 0 ]]; do
  fact=$((fact * num))
  num=$((num - 1))
done
echo fact