You can find this course on Learnshell.org

My GitHub Repo with exercices art-dambrine/learnshell @GitHub

1/ Hello, World! - Intro

To execute, simply write the shell script file name, once the file has execute permission (chmod +x filename).

Note
The first line of the shell script file begins with a "sha-bang" (#!)

Adding comments

Any text following the "#" is considered a comment

Find out what is currently active shell

ps | grep $$
which bash

2/ Variables

Note
Shell variables are created once they are assigned a value.

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.

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"

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

3/ Passing arguments to the script

Inside the script, the $1 variable references the first argument in the command line.

The $0 variable references to the current script

The variable $# holds the number of arguments passed to the script

echo $# --> results with: 6
Note
The variable $@ holds a space delimited string of all arguments passed to the script

4/ Arrays

To create an array in bash space-delimited values enclosed in ()

my_array=(apple banana "Fruit Basket" orange)
new_array[2]=apricot

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]}     # carrot

5/ Array comparison

# basic construct
# array=(value1 value2 ... valueN)
array=(23 45 34 1 2 3)
#To refer to a particular value (e.g. : to refer 3rd value)
echo ${array[2]}

#To refer to all the array values
echo ${array[@]}

#To evaluate the number of elements in an array
echo ${#array[@]}

6/ Basic Operators

Arithmetic Operators

Simple arithmetics on variables can be done using the arithmetic expression: $expression

A=3
B=$((100 * $A + 5)) # 305

Some operators you might not know

  1. a % b modulo (the integer remainder of a divided by b)

  2. a ** b exponentiation (a to the power of b)

7/ Basic String Operations

The shell allows some common string operations which can be very useful for script writing.

String Length

#       1234567890123456
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
Note
If :$LEN is omitted, 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" ','`

# 6 is size of the word 'first=' and 1 is the size of a char comma
LENGTH=`expr $COMMA2 - 6 - 1`

FIRSTNAME=${CHOP1FIELD:6:$LENGTH}      # Johnny Boy
echo $FIRSTNAME

Substring Replacement

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-%m-%d)}    # to be or not to be on 2012-06-14

8/ Decision making

The shell also supports logical decision making.

if [ expression ]; then

code if 'expression' is true

fi

Shell syntax for decision making

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

Comparisons

Numeric

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

String

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
Note
whitespace around = is required
Note
use "" around string variables to avoid shell expansion of special characters as *

Case structure

case "$variable" in
    "$condition1" )
        command...
    ;;
    "$condition2" )
        command...
    ;;
esac

Exemple for simple case

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

9/ Loops

Bash for loop

Note
it’s a foreach
# basic construct
for arg in [list]
do
 command(s)...
done

For each pass through the loop, arg takes on the value of each successive value in the list. Then the command(s) are executed.

# loop on array member
NAMES=(Joe Jenny Sara Tony)
for N in ${NAMES[@]} ; do
  echo "My name is $N"
done

# loop on command output results
for f in $( ls prog.sh /etc/localtime ) ; do
  echo "File is: $f"
done

Bash while loop

# basic construct
while [ condition ]
do
 command(s)...
done

The while construct tests for a condition, and if true, executes commands. It keeps looping as long as the condition is true.

COUNT=4
while [ $COUNT -gt 0 ]; do
  echo "Value of count is: $COUNT"
  COUNT=$(($COUNT - 1))
done

Bash until loop

# basic construct
until [ condition ]
do
 command(s)...
done

The until construct tests for a condition, and if false, executes commands. It keeps looping as long as the condition is false (opposite of while construct)

COUNT=1
until [ $COUNT -gt 5 ]; do
  echo "Value of count is: $COUNT"
  COUNT=$(($COUNT + 1))
done

Break and continue statements

break and continue can be used to control the loop execution of for, while and until constructs. continue is used to skip the rest of a particular loop iteration, whereas break is used to skip the entire rest of loop. A few examples:

# Prints out 0,1,2,3,4

COUNT=0
while [ $COUNT -ge 0 ]; do
  echo "Value of COUNT is: $COUNT"
  COUNT=$((COUNT+1))
  if [ $COUNT -ge 5 ] ; then
    break
  fi
done

# Prints out only odd numbers - 1,3,5,7,9
COUNT=0
while [ $COUNT -lt 10 ]; do
  COUNT=$((COUNT+1))
  # Check if COUNT is even
  if [ $(($COUNT % 2)) = 0 ] ; then
    continue
  fi
  echo $COUNT
done