Shell / Bash Scripting

Shell Interaction

Kernel

The kernel is a computer program that is the core of a computer’s operating system, with complete control over everything in the system.

It manages following resources of the Linux system:

Notes:

  • It is often mistaken that Linus Torvalds has developed Linux OS, but actually he is only responsible for development of Linux kernel.
  • Complete Linux system = Kernel + GNU system utilities and libraries + other management scripts + installation scripts.

Shell

Shell is broadly classified into two categories:

Command Line Shell

Graphical Shell

There are several shells are available for Linux systems.Each shell does the same job but understand different commands and provide different built in functions.

Shell Scripting

Why do we need shell scripts

There are many reasons to write shell scripts:

Advantages of shell scripts
Disadvantages of shell scripts

Writing Shell Scripts

Read user input
#!/bin/bash
echo "What is your name?"
read name
echo "Hello! $name"

Variables

Variable Names:

The name of a variable can contain only letters (a to z or A to Z), numbers ( 0 to 9) or the underscore character (_).

The reason we cannot use other characters such as !, *, or - is that these characters have a special meaning for the shell.

Defining Variables
variable_name=variable_value

Examples:

NAME="Astik Anand"
VAR2=100
Accessing Values

To access the value stored in a variable, prefix its name with the dollar sign $.

NAME="Astik Anand"
echo $NAME
Read-only Variables

Shell provides a way to mark variables as read-only by using the read-only command.

NAME="Astik Anand"
readonly NAME
NAME="Anand"

The above script will say This variable is read only.

Unsetting Variables

Unsetting or deleting a variable directs the shell to remove the variable from the list of variables that it tracks.

unset variable_name

Example:

NAME="Astik Anand"
unset NAME
echo $NAME

This will not print anything.

Note: We cannot use the unset command to unset variables that are marked readonly.

Variable Types


Command-Line Arguments

The command-line arguments $1, $2, $3, …$9 are positional parameters, with $0 pointing to the actual command, program, shell script, or function and $1, $2, $3, …$9 as the arguments to the command.

echo "File Name: $0"
echo "First Parameter : $1"
echo "Second Parameter : $2"
echo "Quoted Values: $@"
echo "Quoted Values: $*"
echo "Total Number of Parameters : $#"

Special Parameters $* and $@

There are special parameters that allow accessing all the command-line arguments at once. $* and $@ both will act the same unless they are enclosed in double quotes, “”.

Both the parameters specify the command-line arguments. However, the $* special parameter takes the entire list as one argument with spaces between and the $@ special parameter takes the entire list and separates it into separate arguments.

We can write the shell script as shown below to process an unknown number of commandline arguments with either the $* or $@ special parameters −

for TOKEN in $*
do
   echo $TOKEN
done


Arrays

Defining Array Values

We can use a single array to store many values in one variable.

array_name[index]=value
Accessing Array Values

After you have set any array variable, you access it as follows −

${array_name[index]}

You can access all the items in an array in one of the following ways −

${array_name[*]}
${array_name[@]}

Example:

NAME[0]="Astik"
NAME[1]="Anand"
NAME[2]="Manpal"
NAME[3]="Vasram"
NAME[4]="Santosh"
echo "First Index: ${NAME[0]}"
echo "Second Index: ${NAME[1]}"
echo "First Method: ${NAME[*]}"
echo "Second Method: ${NAME[@]}"


Operators

Bourne shell didn’t originally have any mechanism to perform simple arithmetic operations but it uses external programs, either awk or expr.

val=`expr 2 + 2`
echo "Total value : $val"

Output

Total value : 4

The following points need to be considered while adding:

Arithmetic Operators
* Addition: `expr $a + $b`
* Subtraction: `expr $a - $b`
* Multiplication: `expr $a \* $b`
* Division: `expr $b / $a`
* Modulus: `expr $b % $a`
* Assignment: a = $b
* Equality: [ $a == $b ]
* Not Equality: [ $a != $b ]

Note:It is very important to understand that all the conditional expressions should be inside square braces with spaces around them, for example [ $a == $b ] is correct whereas, [$a==$b] is incorrect.

Relational Operators:
* Equality:	[ $a -eq $b ]
* Not Equality: [ $a -ne $b ]
* Greater than: [ $a -gt $b ]
* Lesser than: [ $a -lt $b ]
* Greater and Equal: [ $a -ge $b ]
* Lesser than and Equal: [ $a -le $b ]


Important Note: It is very important to understand that all the conditional expressions should be placed inside square braces with spaces around them. For example, [ $a <= $b ] is correct whereas, [$a <= $b] is incorrect.

Boolean Operators
* Negation: [ ! false ]
* OR: [ $a -lt 20 -o $b -gt 100 ]
* AND: [ $a -lt 20 -a $b -gt 100 ]


String Operators
* Equality:	[ $a = $b ]
* Not Equality: [ $a != $b ]
* Size Zero: [ -z $a ]
* Size Non-zero: [ -n $a ]
* Not Empty: [ $a ]



Decision Making

The if…else statements

Unix Shell supports following forms of if…else statement:

The case…esac Statement


Loop Controls

While Loop
#!/bin/sh

a=0
while [ "$a" -lt 10 ]    # this is loop1
do
   b="$a"
   while [ "$b" -ge 0 ]  # this is loop2
   do
      echo -n "$b "
      b=`expr $b - 1`
   done
   echo
   a=`expr $a + 1`
done


Output:

0
1 0
2 1 0
3 2 1 0
4 3 2 1 0
5 4 3 2 1 0
6 5 4 3 2 1 0
7 6 5 4 3 2 1 0
8 7 6 5 4 3 2 1 0
9 8 7 6 5 4 3 2 1 0


Example: Script to jump into directory instead of recursive cd

# A simple bash script to move up to desired directory level directly
 
function jump(){
    # original value of Internal Field Separator
    OLDIFS=$IFS
 
    # setting field separator to "/" 
    IFS=/
 
    # converting working path into array of directories in path
    # eg. /my/path/is/like/this
    # into [, my, path, is, like, this]
    path_arr=($PWD)
 
    # setting IFS to original value
    IFS=$OLDIFS
 
    local pos=-1
 
    # ${path_arr[@]} gives all the values in path_arr
    for dir in "${path_arr[@]}"
    do
        # find the number of directories to move up to
        # reach at target directory 
        pos=$[$pos+1]
        if [ "$1" = "$dir" ];then
 
            # length of the path_arr
            dir_in_path=${#path_arr[@]}
 
            #current working directory
            cwd=$PWD
            limit=$[$dir_in_path-$pos-1]
            for ((i=0; i<limit; i++))
            do
                cwd=$cwd/..
            done
            cd $cwd
            break
        fi
    done
}


For now we cannot execute our shell script because it do not have permissions. We have to make it executable by provinding execute permissions by typing following command.

$ chmod u+x path/to/our/file/jump.sh

Now to make this available on every terminal session, we have to put this in .bashrc file. .bashrc is a shell script that Bash shell runs whenever it is started interactively. The purpose of a .bashrc file is to provide a place where you can set up variables, functions and aliases, define our prompt and define other settings that we want to use whenever we open a new terminal window.

Now open terminal and type following command to make jump available as command in terminal.

$ echo "source path/to/our/file/jump.sh">> ~/.bash_profile

Now open you terminal and try out new jump functionality by typing following command.

$ jump dir_name