Whether you are an experienced programmer or not, this article is intended for everyone who wishes to learn programming with Unix/Linux shell interpreters.
The article discusses shell programming in general with focus on Bash ("Bourne Again Shell") shell as the main shell interpreter. Shell programming using other common shells such as sh, csh, tcsh, will also be referenced, as they sometime differ from bash.
Shell programming can be accomplished by directly executing shell commands at the shell prompt or by storing them in the order of execution, in a text file, called a shell script, and then executing the shell script. To execute, simply write the shell script file name, once the file has execute permission (chmod +x filename).
The first line of the shell script file begins with a "sha-bang" (#!) which is not read as a comment, followed by the full path where the shell interpreter is located. This path, tells the operating system that this file is a set of commands to be fed into the interpreter indicated. Note that if the path given at the "sha-bang" is incorrect, then an error message e.g. "Command not found.", may be the result of the script execution. It is common to name the shell script with the ".sh" extension. The first line may look like this:
#! /bin/bash
Adding comments
any text following the "#" is considered a comment. To find out what is currently active shell, and what is its path, type the highlighted command at the shell prompt (sample responses follow): Command:
ps | grep $$
Response :
987 tty1 00:00:00 bash
This response shows that the shell you are using is of type 'bash'. next find out the full path of the shell interpreter
which bash
Or
Whence bash
expected response
/bin/bash
This response shows the full execution path of the shell interpreter. Make sure that the "sha-bang" line at the beginning of your script, matches this same execution path.
hello world in bash
To print hello world in bash , use either the echo or print keyword I.e
echo "hello, world!"
The major difference between echo and print is that print return a zero value after printing to the shell.
Variables
Shell variables are created once they are assigned a value. A variable can contain a number, a character or a string of characters. Variable name is case sensitive and can consist of a combination of letters and the underscore "_". Value assignment is done using the "=" sign. Note that no space permitted on either side of = sign when initializing variables.
Name="Mahmud"
Age=20
Date_of_birth="13-01-2000"
Referencing the variables
A backslash "\" is used to escape special character meaning
PRICE_PER_APPLE=5
echo "The price of an Apple today is: \$HK $PRICE_PER_APPLE"
Encapsulating the variable name with ${} is used to avoid ambiguity
MyFirstLetters=ABC
echo "The first 10 letters in the alphabet are: ${MyFirstLetters}DEFGHIJ"
Encapsulating the variable name with "" will preserve any white space values
greeting='Hello world!'
echo $greeting" now with spaces: $greeting"
Variables can be assigned with the value of a command output. This is referred to as substitution. Substitution can be done by encapsulating the command with `` (known as back-ticks) or with $()
FILELIST=`ls`
FileWithTimeStamp=/tmp/my-dir/file_$(/bin/date +%Y-%m-%d).txt
Note that when the script runs, it will run the command inside the $() parenthesis and capture its output.
passing shell arguments
Arguments can be passed to the script when it is executed, by writing them as a space-delimited list following the script file name.
Inside the script, the $1 variable references the first argument in the command line, $2 the second argument and so forth. The variable $0 references to the current script. In the following example, the script name is followed by 6 arguments.
Example
my_shopping.sh file contains below code.
#!/bin/bash
echo "File name is "$0 # holds the current script
echo $3 # $3 holds banana
Data=$5
echo "A $Data costs just $6."
echo $#
Executing the script on terminal as,
bash my_shopping.sh apple 5 banana 8 "Fruit Basket" 15
output is
File name is my_shopping.sh
banana
A Fruit Basket costs just 15
6
The variable $# holds the number of arguments passed to the script
The variable $@ holds a space delimited string of all arguments passed to the script.
Arrays
An array can hold several values under one name. Array naming is the same as variables naming. An array is initialized by assign space-delimited values enclosed in ()
my_array=(apple banana "Fruit Basket" orange)
new_array[2]=apricot
Array members need not be consecutive or contiguous. Some members of the array can be left uninitialized.
The total number of elements in the array is referenced by
${#arrayname[@]}
my_array=(apple banana "Fruit Basket" orange)
echo ${#my_array[@]} # 4
The array elements can be accessed with their numeric index. The index of the first element is 0.
my_array=(apple banana "Fruit Basket" orange)
echo ${my_array[3]} # orange
- note that curly brackets are needed .
Adding another array element
my_array[4]="carrot" # value assignment without a $ and curly brackets
echo ${#my_array[@]} # 5
echo ${my_array[${#my_array[@]}-1
Basic Operators
Arithmetic Operators
Simple arithmetics on variables can be done using the arithmetic expression:
$((expression))
For example:
A=3
B=$((100 * $A + 5)) # 305
The basic operators are:
a + b addition (a plus b)
a - b substraction (a minus b)
a * b multiplication (a times b)
a / b division (integer) (a divided by b)
a % b modulo (the integer remainder of a divided by b)
a ** b exponentiation (a to the power of b)
Basic String Operations
The shell allows some common string operations which can be very useful for script writing.
String Length
STRING="this is a string"
echo ${#STRING} # 16
Index
Find the numerical position in $STRING of any single character in $SUBSTRING that matches. Note that the 'expr' command is used in this case.
STRING="this is a string"
SUBSTRING="hat"
expr index "$STRING" "$SUBSTRING" # 1 is the position of the first 't' in $STRING
Substring Extraction
Extract substring of length $LEN from $STRING starting after position $POS. Note that first position is 0.
STRING="this is a string"
POS=1
LEN=3
echo ${STRING:$POS:$LEN} # his
If :$LEN is omitted, it will extract substring from $POS to end of line
STRING="this is a string"
echo ${STRING:1} # $STRING contents without leading character
echo ${STRING:12} # ring
Simple data extraction example:
# Code to extract the First name from the data record
DATARECORD="last=Clifford,first=Johnny Boy,state=CA"
COMMA1=`expr index "$DATARECORD" ','` # 14 position of first comma
CHOP1FIELD=${DATARECORD:$COMMA1} #
COMMA2=`expr index "$CHOP1FIELD" ','`
LENGTH=`expr $COMMA2 - 6 - 1`
FIRSTNAME=${CHOP1FIELD:6:$LENGTH} # Johnny Boy
echo $FIRSTNAME
Substring Replacement
STRING="to be or not to be"
- Replace first occurrence of substring with replacement
STRING="to be or not to be" echo ${STRING[@]/be/eat} # to eat or not to be
- Replace all occurrences of substring
STRING="to be or not to be" echo ${STRING[@]//be/eat} # to eat or not to eat
- Delete all occurrences of substring (replace with empty string)
STRING="to be or not to be" echo ${STRING[@]// not/} # to be or to be
- Replace occurrence of substring if at the beginning of $STRING
STRING="to be or not to be" echo ${STRING[@]/#to be/eat now} # eat now or not to be
- Replace occurrence of substring if at the end of $STRING
STRING="to be or not to be" echo ${STRING[@]/%be/eat} # to be or not to eat
- replace occurrence of substring with shell command output
STRING="to be or not to be" echo ${STRING[@]/%be/be on $(date +%Y-
Decision Making
As in popular programming languages, the shell also supports logical decision making.
The basic conditional decision making construct is:
if [ expression ]; then
code if 'expression' is true
fi
NAME="John"
if [ "$NAME" = "John" ]; then
echo "True - my name is indeed John"
fi
It can be expanded with 'else'
NAME="Bill"
if [ "$NAME" = "John" ]; then
echo "True - my name is indeed John"
else
echo "False"
echo "You must mistaken me for $NAME"
fi
It can be expanded with 'elif' (else-if)
NAME="George"
if [ "$NAME" = "John" ]; then
echo "John Lennon"
elif [ "$NAME" = "George" ]; then
echo "George Harrison"
else
echo "This leaves us with Paul and Ringo"
fi
The expression used by the conditional construct is evaluated to either true or false. The expression can be a single string or variable. A empty string or a string consisting of spaces or an undefined variable name, are evaluated as false. The expression can be a logical combination of comparisons: negation is denoted by !, logical AND (conjunction) is denoted by &&, and logical OR (disjunction) is denoted by ||. Conditional expressions should be surrounded by double brackets [[ ]].
Types of numeric comparisons comparison Evaluated to true when $a -lt $b $a < $b $a -gt $b $a > $b $a -le $b $a <= $b $a -ge $b $a >= $b $a -eq $b $a is equal to $b $a -ne $b $a is not equal to $b Types of string comparisons comparison Evaluated to true when "$a" = "$b" $a is the same as $b "$a" == "$b" $a is the same as $b "$a" != "$b" $a is different from $b -z "$a" $a is empty note1: whitespace around = is required
note2: use "" around string variables to avoid shell expansion of special characters as *
Logical combinations if [[ $VAR_A[0] -eq 1 && ($VAR_B = "bee" || $VAR_T = "tee") ]] ; then command... fi case structure case "$variable" in "$condition1" ) command... ;; "$condition2" ) command... ;; esac simple case bash structure
mycase=1
case $mycase in
1) echo "You selected bash";;
2) echo "You selected perl";;
3) echo "You selected phyton";;
4) echo "You selected c++";;
5) exit
esac
With that , we have concluded the basics of shell scripting