7. Bash scripting¶
A bash script is a file containing commands that can run on the bash shell. They usually have the .sh
extension.
A minimal example¶
#!/usr/bin/env bash
# A simple bash script
echo "Hello World"
Note
#!
is called the “shebang”. It indicates the path to the program/interpreter that would be used to execute the script.
Execution¶
$ ./myscript.sh
bash: ./myscript.sh: Permission denied
$ ls -l myscript.sh
-rw-r--r-- 18 dkishore users 4096 Jun 10 09:12 myscript.sh
- The permissions on the script need to be changed to allow for execution -
chmod +x myscript.sh
- The file can be executed either as
./myscript.sh
orbash myscript.sh
Variables¶
#!/bin/bash
cp $1 $2
# Verification
echo Details for $2
ls -lh $2
$1
and $2
are the first and second arguments to the script.
Note
$0
refers to the name of the bash script$#
refers to the number of arguments passed to the script$@
refers to all the arguments supplied$?
refers to the exit status of the most recent process
Setting your own variables:
#!/bin/bash
myvariable=Hello
anothervar=Fred
echo $myvariable $anothervar
sampledir=/etc
echo $sampledir
Note
- Use quotes if your value has a space. Eg:
myvar="Hello World!"
- When referring to or reading a variable we place a
$
sign before the variable name - When setting a variable we leave out the
$
sign - Do not use white-space around the
=
- var=23, that’s the correct variable assignment syntax: a word that consists of unquoted letters followed by an unquoted = that appears before a command argument (here it’s on its own)
- var =23, the var command with =23 as argument (except in zsh where =something is a special operator that expands to the path of the something command. Here, you’d likely to get an error as 23 is unlikely to be a valid command name).
- var= 23, an assignment var= followed by a command name 23. That’s meant to execute 23 with var= passed to its environment (var environment variable with an empty value).
- var = 23, var command with = and 23 as argument. Try with echo = 23 for instance.
- Do not use white-space around the
Command Substitution¶
myvar=$( ls /etc | wc -l )
echo $myvar
Command substitution is nice and simple if the output of the command is a single word or line. If the output goes over several lines then the newlines are simply removed and all the output ends up on a single line.
Exporting variables¶
Scripts are run in their own process hence you cannot use a variable you assign outside of the script, in the script. To use external variables they need to be exported.
script1.sh
#!/bin/bash
# demonstrate variable scope 1.
var1=blah
var2=foo
# Let's verify their current value
echo $0 :: var1 : $var1, var2 : $var2
export var1
./script2.sh
# Let's see what they are now
echo $0 :: var1 : $var1, var2 : $var2
script2.sh
#!/bin/bash
# demonstrate variable scope 2
# Let's verify their current value
echo $0 :: var1 : $var1, var2 : $var2
# Let's change their values
var1=flop
var2=bleh
result
./script1.sh
script1.sh :: var1 : blah, var2 : foo
script2.sh :: var1 : blah, var2 :
script1.sh :: var1 : blah, var2 : foo
Input¶
#!/bin/bash
# Ask the user for their name
echo Hello, who am I talking to?
read varname
echo It\'s nice to meet you $varname
Run the command read and save the users response into the variable varname
.
Arithmetic¶
let
#!/bin/bash
# Basic arithmetic using let
let a=5+4
echo $a # 9
let "a = 5 + 4"
echo $a # 9
let a++
echo $a # 10
let "a = 4 * 5"
echo $a # 20
let "a = $1 + 30"
echo $a # 30 + first command line argument
expr
#!/bin/bash
# Basic arithmetic using expr
expr 5 + 4 # 9
expr "5 + 4" # 5 + 4
expr 5+4 # 5+4
expr 5 \* $1
expr 11 % 2
a=$( expr 10 - 3 )
echo $a # 7
double parentheses
#!/bin/bash
# Basic arithmetic using double parentheses
a=$(( 4 + 5 ))
echo $a # 9
a=$((3+5))
echo $a # 8
b=$(( a + 3 ))
echo $b # 11
b=$(( $a + 4 ))
echo $b # 12
(( b++ ))
echo $b # 13
(( b += 3 ))
echo $b # 16
a=$(( 4 * 5 ))
echo $a # 20
If statements¶
If
statements
#!/bin/bash
# Basic if statement
if [ $1 -gt 100 ]
then
echo "Hey that\'s a large number."
pwd
fi
- The square brackets in the if statement is a reference to the
test
command. -gt
is equivalent to >=. Similarly there are!
,-n
,-z
,=
,!=
and many more.- Can be alternatively used as
test 001 = 1
. (This won’t return anything you can test the exit status using$?
. 0 means TRUE and 1 means FAILURE).
If-else
#!/bin/bash
# else example
if [ $# -eq 1 ]
then
nl $1
else
nl /dev/stdin
fi
If-else-if
#!/bin/bash
# elif statements
if [ $1 -ge 18 ]
then
echo "You may go to the party."
elif [ $2 == 'yes' ]
then
echo "You may go to the party but be back before midnight."
else
echo "You may not go to the party."
fi
Case
statements
#!/bin/bash
# case example
case $1 in
start)
echo starting
;;
stop)
echo stoping
;;
restart)
echo restarting
;;
*)
echo "don\'t know"
;;
esac
Note
The ;;
are used as break statements
Loops¶
while
loop
#!/bin/bash
# Basic while loop
counter=1
while [ $counter -le 10 ]
do
echo $counter
((counter++))
done
echo "All done"
until
loop
#!/bin/bash
# Basic until loop
counter=1
until [ $counter -gt 10 ]
do
echo $counter
((counter++))
done
echo "All done"
The until
loop is the exact opposite of the while
loop
for
loops
#!/bin/bash
# Basic for loop
names='Stan Kyle Cartman Kenny' # is one way to define lists
for name in $names
do
echo $name
done
echo All done
- Ranges and Iterators
#!/bin/bash
# Basic range in for loop
for value in {1..5}
do
echo $value
done
echo All done
Note
- You can have custom range by providing a step. Eg.
{10..0..2}
- GNU
seq
can also be used to create custom iterators. Eg.seq 10 -2 0
Functions¶
- Simple example
#!/bin/bash
# Basic function
print_something () {
echo Hello I am a function
}
print_something
- Passing arguments
#!/bin/bash
# Passing arguments to a function
print_something () {
echo Hello $1
}
print_something Mars
print_something Jupiter
- Return values
Bash functions don’t allow for return values however they allow for a return status
#!/bin/bash
# Setting a return status for a function
print_something () {
echo Hello $1
return 5
}
print_something Mars
print_something Jupiter
echo The previous function has a return value of $?
- Variable scope
#!/bin/bash
# Experimenting with variable scope
var_change () {
local var1='local 1'
echo Inside function: var1 is $var1 : var2 is $var2
var1='changed again'
var2='2 changed again'
}
var1='global 1'
var2='global 2'
echo Before function call: var1 is $var1 : var2 is $var2
var_change
echo After function call: var1 is $var1 : var2 is $var2
result
Before function call: var1 is global 1 : var2 is global 2
Inside function: var1 is local 1 : var2 is global 2
After function call: var1 is global 1 : var2 is 2 changed again