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
.
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.
practice : more scripting
-
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
-
Improve the previous script to test that the numbers are between 1 and 100, exit with an error if necessary.
-
Improve the previous script to congratulate the user if the sum equals the product.
-
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.
-
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
-
Write a script that asks for two numbers, and outputs the sum and product (as shown here).
-
Improve the previous script to test that the numbers are between 1 and 100, exit with an error if necessary.
-
Improve the previous script to congratulate the user if the sum equals the product.
-
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
-
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.