more scripting
(Written by Paul Cobbaut, https://github.com/paulcobbaut/, with contributions by: Alex M. Schapelle, https://github.com/zero-pytagoras/)
eval
eval
reads arguments as input to the shell (the
resulting commands are executed). This allows using the value of a
variable as a variable.
student@linux:~/test42$ answer=42
student@linux:~/test42$ word=answer
student@linux:~/test42$ eval x=\$$word ; echo $x
42
Both in bash
and Korn
the arguments can be quoted.
kahlan@solexp11$ answer=42
kahlan@solexp11$ word=answer
kahlan@solexp11$ eval "y=\$$word" ; echo $y
42
Sometimes the eval
is needed to have correct parsing of arguments.
Consider this example where the date
command receives one parameter
1 week ago
.
student@linux~$ date --date="1 week ago"
Thu Mar 8 21:36:25 CET 2012
When we set this command in a variable, then executing that variable
fails unless we use eval
.
student@linux~$ lastweek='date --date="1 week ago"'
student@linux~$ $lastweek
date: extra operand `ago"'
Try `date --help' for more information.
student@linux~$ eval $lastweek
Thu Mar 8 21:36:39 CET 2012
(( ))
The (( ))
allows for evaluation of numerical
expressions.
student@linux:~/test42$ (( 42 > 33 )) && echo true || echo false
true
student@linux:~/test42$ (( 42 > 1201 )) && echo true || echo false
false
student@linux:~/test42$ var42=42
student@linux:~/test42$ (( 42 == var42 )) && echo true || echo false
true
student@linux:~/test42$ (( 42 == $var42 )) && echo true || echo false
true
student@linux:~/test42$ var42=33
student@linux:~/test42$ (( 42 == var42 )) && echo true || echo false
false
let
The let
built-in shell function instructs the shell to
perform an evaluation of arithmetic expressions. It will return 0 unless
the last arithmetic expression evaluates to 0.
[student@linux ~]$ let x="3 + 4" ; echo $x
7
[student@linux ~]$ let x="10 + 100/10" ; echo $x
20
[student@linux ~]$ let x="10-2+100/10" ; echo $x
18
[student@linux ~]$ let x="10*2+100/10" ; echo $x
30
The shell
can also convert between different bases.
[student@linux ~]$ let x="0xFF" ; echo $x
255
[student@linux ~]$ let x="0xC0" ; echo $x
192
[student@linux ~]$ let x="0xA8" ; echo $x
168
[student@linux ~]$ let x="8#70" ; echo $x
56
[student@linux ~]$ let x="8#77" ; echo $x
63
[student@linux ~]$ let x="16#c0" ; echo $x
192
There is a difference between assigning a variable directly, or using
let
to evaluate the arithmetic expressions (even if it is just
assigning a value).
kahlan@solexp11$ dec=15 ; oct=017 ; hex=0x0f
kahlan@solexp11$ echo $dec $oct $hex
15 017 0x0f
kahlan@solexp11$ let dec=15 ; let oct=017 ; let hex=0x0f
kahlan@solexp11$ echo $dec $oct $hex
15 15 15
case
You can sometimes simplify nested if statements with a
case
construct.
[student@linux ~]$ ./help
What animal did you see ? lion
You better start running fast!
[student@linux ~]$ ./help
What animal did you see ? dog
Don't worry, give it a cookie.
[student@linux ~]$ cat help
#!/bin/bash
#
# Wild Animals Helpdesk Advice
#
echo -n "What animal did you see ? "
read animal
case $animal in
"lion" | "tiger")
echo "You better start running fast!"
;;
"cat")
echo "Let that mouse go..."
;;
"dog")
echo "Don't worry, give it a cookie."
;;
"chicken" | "goose" | "duck" )
echo "Eggs for breakfast!"
;;
"liger")
echo "Approach and say 'Ah you big fluffy kitty...'."
;;
"babelfish")
echo "Did it fall out your ear ?"
;;
*)
echo "You discovered an unknown animal, name it!"
;;
esac
[student@linux ~]$
shell functions
Shell functions
can be used to group commands in a
logical way.
kahlan@solexp11$ cat funcs.ksh
#!/bin/ksh
function greetings {
echo Hello World!
echo and hello to $USER to!
}
echo We will now call a function
greetings
echo The end
This is sample output from this script with a function
.
kahlan@solexp11$ ./funcs.ksh
We will now call a function
Hello World!
and hello to kahlan to!
The end
A shell function can also receive parameters.
kahlan@solexp11$ cat addfunc.ksh
#!/bin/ksh
function plus {
let result="$1 + $2"
echo $1 + $2 = $result
}
plus 3 10
plus 20 13
plus 20 22
This script produces the following output.
kahlan@solexp11$ ./addfunc.ksh
3 + 10 = 13
20 + 13 = 33
20 + 22 = 42
practice : more scripting
1. Write a script that asks for two numbers, and outputs the sum and product (as shown here).
Enter a number: 5
Enter another number: 2
Sum: 5 + 2 = 7
Product: 5 x 2 = 10
2. Improve the previous script to test that the numbers are between 1 and 100, exit with an error if necessary.
3. Improve the previous script to congratulate the user if the sum equals the product.
4. Write a script with a case insensitive case statement, using the shopt nocasematch option. The nocasematch option is reset to the value it had before the scripts started.
5. If time permits (or if you are waiting for other students to finish this practice), take a look at Linux system scripts in /etc/init.d and /etc/rc.d and try to understand them. Where does execution of a script start in /etc/init.d/samba ? There are also some hidden scripts in \~, we will discuss them later.
solution : more scripting
1. Write a script that asks for two numbers, and outputs the sum and product (as shown here).
Enter a number: 5
Enter another number: 2
Sum: 5 + 2 = 7
Product: 5 x 2 = 10
#!/bin/bash
echo -n "Enter a number : "
read n1
echo -n "Enter another number : "
read n2
let sum="$n1+$n2"
let pro="$n1*$n2"
echo -e "Sum\t: $n1 + $n2 = $sum"
echo -e "Product\t: $n1 * $n2 = $pro"
2. Improve the previous script to test that the numbers are between 1 and 100, exit with an error if necessary.
echo -n "Enter a number between 1 and 100 : "
read n1
if [ $n1 -lt 1 -o $n1 -gt 100 ]
then
echo Wrong number...
exit 1
fi
3. Improve the previous script to congratulate the user if the sum equals the product.
if [ $sum -eq $pro ]
then echo Congratulations $sum == $pro
fi
4. Write a script with a case insensitive case statement, using the shopt nocasematch option. The nocasematch option is reset to the value it had before the scripts started.
#!/bin/bash
#
# Wild Animals Case Insensitive Helpdesk Advice
#
if shopt -q nocasematch; then
nocase=yes;
else
nocase=no;
shopt -s nocasematch;
fi
echo -n "What animal did you see ? "
read animal
case $animal in
"lion" | "tiger")
echo "You better start running fast!"
;;
"cat")
echo "Let that mouse go..."
;;
"dog")
echo "Don't worry, give it a cookie."
;;
"chicken" | "goose" | "duck" )
echo "Eggs for breakfast!"
;;
"liger")
echo "Approach and say 'Ah you big fluffy kitty.'"
;;
"babelfish")
echo "Did it fall out your ear ?"
;;
*)
echo "You discovered an unknown animal, name it!"
;;
esac
if [ nocase = yes ] ; then
shopt -s nocasematch;
else
shopt -u nocasematch;
fi
5. If time permits (or if you are waiting for other students to finish this practice), take a look at Linux system scripts in /etc/init.d and /etc/rc.d and try to understand them. Where does execution of a script start in /etc/init.d/samba ? There are also some hidden scripts in \~, we will discuss them later.