---
# System prepended metadata

title: Shell Scripting

---

# Shell Scripting

## Introduction
it is interpreted and not compiled
supported shells in your computer:
cat /etc/shells
sh shell is the original shell and bash is born again shell which is more intuitive and defult in gnu which is instructed here.
to see where bash is located: ```which bash```

to write bash script start with ```#! /bin/bash (location of you bash)```
this is to tell the script where to find bash.
The original file created by touch is not executable --> ```chmod +x hello.sh```

\# is used for comment which would not be executed.

## variables
to store data like string, integer.
1. system variables: defined by Linux in capital letter -> $BASH, $BASH_VERSION, $HOME, $PWD
2. user defined variables
```
name=fateme
echo $name
```

## Read User Input
```
echo "enter your name: "
read name1 name2 name3
echo $name1 $name3
```
keeps the cursor at the line
```
read -p "username: " username
```
not showing what user entered(password):  `read -s`
read into array `read -a names`
if we only have ```read``` then the entered value is saved into `$REPLY`

## Pass argument
1.
`echo $1 $2 $3`
`$0` --> name of shell script
2. pass argument through array
```
arg=("$@")
echo {$arg[0]} --> first element not filename
echo $@ --> all elements
echo $# --> number of elements
```


## if statement
**Example:**
```
if [condition]
then
    echo "condition a is true"
elif [condition]
then
    echo "condition b is true"
else
    echo "condition is false"
fi
```

#### integer comparison:
1. -eq in []
2. -ne
3. -gt
4. -ge
5. -lt
6. -le
7. < =< >= > in (())

#### string comparison:
1. = (equality) in []
2. ==
3. !=
4. <> in [[]]    
5. -z string in null


## File test operator
ceck if file exists, has a certain format...
```
echo -e "enter the name of file: \c"
read filename
```
-e \c keep cursor at the line

1. check if file exists: -f
 ```
    if [ -e $filename ]
    then
        echo "$filename exists"
    else
        echo "$filename not found"
    fi
```
2. check directory: -d
3. check binary file: -b
4. check charcter based file: -c
5. check not empty file: -s
6. has read/write/execute permission: -r/-w/-x


## Append or write text to a file
```
if [ -f $filename ]
then
    if [ -w $filename ]
    then
        echo "write something. to exist press ctrl+d"
        cat >> $filename  --> to append
        cat > $filename  --> to overwrite the file
    else
        echo "$filename doesn't have write permission"
    fi
else
    echo "$filename doesn't exist"
fi
```

## logical AND
1. && with two brakets
2. && with double braket
3. -a
```
age=25
if [ $age -gt 18 ] && [ $age -lt 30 ]
if [ &age -gt 18 -a $age -lt 30 ]
if [[ &age -gt 18 && $age -lt 30 ]]
then 
    echo "age is valid"
fi
```
## logical OR
1. || with two brakets
2. || with double brackets
3. -o

## arithmetic operation
```echo 1+1```
just print 1+1 which takes as string and doesn't do arithmetic operations.
1. $, double paranthesis, space:
```
num1=5
num=20
echo $(( num1 + num2 ))
```
2. $, single paranthesis, expr, $
```
echo $(expr $num1 + $num2)
**for multiplication:**
echo $(expr $num1 \* $num2)
```

## floating point operation
doing the similar operation as above raises syntax error for non integer values.
bc: a language for precision calculation
``` echo "20.5+1.5" | bc```
**| is called pipeline**
Division problem --> gives integer result. To overcome this problem:
```echo "scale=2;20.5/1.5" | bc```

bc can do more than arithmetic operations like power, square root & etc. check for man bc for more info.
we need to use math library for these operations.
example: 
``` echo "scale=2;sqrt(25)" | bc --mathlib (or -l)```

## case statement
```
vehicle=$1
case $vehicle in
    "car" )
        echo "Rent of $vehicle is 100 dollar" ;;
    "bus" )
        echo "Rent of $vehicle is 200 dollar" ;;
    "bike" )
        echo "Rent of $vehicle is 5 dollar" ;;
    * )
        echo "Unknown vehicle" ;;    
esac
```
regular expressions 
1. [a-z] small leters
2. [A-Z] capital letters
3. [0-9] digits
4. ? special characters

LANG is language/local which should be set to C if we want to use these regex.

## Array 
create array with paranthesis and space
```os=('linux' 'windows' 'osx')
echo "${os[@]}"
echo "${os[1]}" --> windows
echo "${!os[@]}" --> gives indices
echo "${#os[@]}" --> gives length
```
to append an element:
```
os[3]="ubuntu"
```
to update a value:
```os[0]="kali"```
to remove an element:
```unset os[2]```
gap and uninitialized elements in bash array is alright. we can even write: ```os[10]="mint"``` and it leaves the indices from 3 to 10 unset.


## While loop
```
while [ condition ]
do
    command1
    command2
done
```
**example**
```
n = 0
while [ n -lt 10 ]
do 
    echo $n
    (( n++ ))
done
```
#### using sleep to give delay
```
n = 0
while [ n -lt 10 ]
do 
    echo $n
    (( n++ ))
    sleep 1
done
```
it gives 1 second of sleep to print the next command.

## open new terminal
```
gnome-terminal &
xterm &
```

## Read file content
1. first method
```
while read p
do
    echo $p
done < filename
```
2. second method using pipe
```
cat filename | while read p
do
    echo $p
done
```
3. third method specially used for special characters with IFS
IFS: Internal Field Seperator and in ' ' we say recognize boundaries based on white space
```
while IFS=' ' read -r line
do
    echo $line
done < filename
```


## UNTIL loop
like while loop with small difference: in while loop until the expression is true the commands are executed but in until loop until the expression is false the commands are executed.
```
until [ condition ]
do 
    command1
    command2
done
```

## FOR loop
1. used for variable in an array
2. used to loop inside files
3. used for linux commandline
4. used like a c for loop
```
for VARIABLE in 1 2 3 .. N
for VARIABLE in file1 file2 file3
for VARIABLE in $(Linux command here)
for (( EXP1; EXP2; EXP3))
do
    command1
    command2
done
```
example:
1.
```
for i in 1 2 3
do
    echo $i
done
```
2.
only works for bash version greater than 4
```
echo ${BASH_VERSION}
for i in {1..10} --> {START..END..INCREMENT}
do
    echo $i
done
```
3.
```
for (( i=0; i<5; i++ ))
do
    echo $i
done
```
4.
```
for command in ls pwd date
do
    echo "-------$command-------"
    $command
done
```
5. show all files in a directory
```
for item in *
do
    if [ -f $item ]
    then
        echo $item
    fi
done
```
## select loop
select loop is the same as for loop but provides a menu structure to select.
```
select name in john tom ben
do
    echo "$name selected"
done
```
press ctrl+c to exit the menue.

## BREAK and CONTINUE
break is used to jump out of for loop
continue skips normal execution for that condition


## Function
```
function name(){
    command
}
OR
name(){
    command
}
```
To call a function, call it in the script after function definition.
Sequence is important. and is read line by line.
To pass an argument to a function:
```
function print(){
    echo $1 $2
}
print Hello World
```
by default variables in a function are global. If we want it to be local to the function we should define as: ```local name```

## ternary if
```
[[ -f $filename ]] && return 0 || return 1

```
## readonly command
```
var=15
readonly var
var=50
```

this raises an error that var is readonly

to make a function readonly we need flag -f

readonly --> shows all readonly variables
readonly -f --> shows all readonly functions

## Signals and traps
show PID:
``` echo "$$"```

exit 0 to exit bash script successfully
Interrupt signal --> ctrl+C
ctrl+Z --> suspand signal
kill -9 --> SIGKILL

you can see different signals by man 7 signal

trap is used to catch the signal when a signal is recieved. However it doesn't catch SIGKILL and SIGSTOP.
```
trap "echo exit signal" SIGINTERUPT

exit 0
``` 
example:
```
filename=/tmp/test
trap "rm -f $filename; exit" 0 2 15
```
this removes the filename incase corresponding signals are executed.


## bash debugging
1. when running the script: bash -x ./hello.sh (name of script)
2. set option: #!bin/bash -x at the top of script
3. set -x after !#bin/bash and set +x deactivate debuggin

