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
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:
;;
at the end of each block
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