Chapter 26. more scripting

Table of Contents

eval
(( ))
let
case
shell functions
practice : more scripting
solution : more scripting

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.

paul@deb503:~/test42$ answer=42
paul@deb503:~/test42$ word=answer
paul@deb503:~/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.

paul@debian6~$ 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.

paul@debian6~$ lastweek='date --date="1 week ago"'
paul@debian6~$ $lastweek
date: extra operand `ago"'
Try `date --help' for more information.
paul@debian6~$ eval $lastweek
Thu Mar  8 21:36:39 CET 2012

(( ))

The (( )) allows for evaluation of numerical expressions.

paul@deb503:~/test42$ (( 42 > 33 )) && echo true || echo false
true
paul@deb503:~/test42$ (( 42 > 1201 )) && echo true || echo false
false
paul@deb503:~/test42$ var42=42
paul@deb503:~/test42$ (( 42 == var42 )) && echo true || echo false
true
paul@deb503:~/test42$ (( 42 == $var42 )) && echo true || echo false
true
paul@deb503:~/test42$ var42=33
paul@deb503:~/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.

[paul@RHEL4b ~]$ let x="3 + 4" ; echo $x
7
[paul@RHEL4b ~]$ let x="10 + 100/10" ; echo $x
20
[paul@RHEL4b ~]$ let x="10-2+100/10" ; echo $x
18
[paul@RHEL4b ~]$ let x="10*2+100/10" ; echo $x
30
		

The shell can also convert between different bases.

[paul@RHEL4b ~]$ let x="0xFF" ; echo $x
255
[paul@RHEL4b ~]$ let x="0xC0" ; echo $x
192
[paul@RHEL4b ~]$ let x="0xA8" ; echo $x
168
[paul@RHEL4b ~]$ let x="8#70" ; echo $x
56
[paul@RHEL4b ~]$ let x="8#77" ; echo $x
63
[paul@RHEL4b ~]$ 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.

[paul@RHEL4b ~]$ ./help
What animal did you see ? lion
You better start running fast!
[paul@RHEL4b ~]$ ./help
What animal did you see ? dog
Don't worry, give it a cookie.
[paul@RHEL4b ~]$ 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
[paul@RHEL4b ~]$ 			
		

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.