UNIT- 6
Essential Shell Programming
Output Statements: The output statement in the Korn shell is the print command. Although the Korn shell also supports the echo command (inherited from the Bourne shell), we use print because it is faster and because there is the possibility that echo may become deprecated in a future version of the Korn shell.
Syntax:
Figure 1
Example:
$ time=4:30pm
$ print "It is now $time"
It is now 4:30pm
$ time = 4:30pm
Sprint "it is now" Stime
It is now 4:30pm
The print command automatically adds a terminating newline after the last argument. If for some reason we don't want a newline, we can use the - n option. To help format the output, there are nine C-like escape codes that can be used. When using these codes, they must be enclosed in quotes.
Code | Usage |
\b | Backspace |
\c | No new line same as –n |
\n | New line |
\f | Form feed |
\r | Carriage return |
\t | Tab |
\v | Vertical Tab |
\\ | To print backslash |
\Oddd | Octal code for ascii character to be printed |
Input statement: Reading data from a terminal or a file is done using the read command. The read command reads a line and stores the words in variables. It must be terminated by a return, and the input line must immediately follow the command.
Syntax:
Figure 2
When the read command is executed, the shell reads a line from the standard input (keyboard or redirected file) and stores it in variables word by word. Words are characters separated by spaces or tabs. The first word is stored in the first variable, the second is stored in the second variable, and so forth. Another way of saying this is that the read command parses the input string (line) into words. If there are more words than there are variables, all the extra words are placed in the last variable. If there are fewer words than there are variables, the unmatched variables are set to a null value. Any value in them before the read is lost.
The below example demonstrates the use of the read command. The first example demonstrates what happens when not enough words are input. The word is null. In the second example, there are too many words. After the read, we print the variables and then just the third so that we can see exactly what happens. In each case, the first word is separated from the second word by a tab, and the rest of the words are separated by one or more spaces.
Example: $ read word1 word2 word3 Hello Hi $print word1 Hello $print word2 Hi $print word3 Null
$ read word1 word2 word3 Hello Hi How Are You Doing $print word1 Hello $print word2 Hi $print word3 How Are You Doing
Reading line by line: The design for handling extra words provides an easy technique for storing a whole line in one variable. We simply use the read command, giving it only one variable. When executed, the whole line is in the variable. Example: $ read line Now is the time for all good students $ print $line Now is the time for all good students
Reading from a file: The Korn shell allows scripts to read from a user file. This is done with the stream descriptor option (-u). A stream descriptor is a numeric designator for a file. The standard streams are numbered 0, 1, and 2 for standard input, standard output and standard error. Each read command reads the next line from the file. There is no space between the option and the stream descriptor. $read u4 variable_name |
In the Korn shell, when a command is executed, it returns a value known as the exit status of the command. The exit status is stored in a shell variable with a name of (?). Like all named variables, the exit status is accessible by using its name ($ ?). If a command completes successfully, it returns a zero value which is interpreted as true; if it does not complete successfully, it returns a nonzero value, which is interpreted as false.
Syntax:
Figure 3
Example: $ Is file* File1 file2 file3.bak $ print $? 0 $is none Cannot access none. No such file or directory. $ print $? 6 |
eval command: The eval.command is used when the Korn shell need to evaluate a command twice before executing it. To understand this, let's look at an example. To generalize a segment of code, we need to store the name of a variable in a second variable and then use the print command to display the value of the original variable. This permits us to reuse the code by placing a different variable in the second one, allowing us to change the variable that is being displayed. The concept is simple the direct approach doesn't work. It fails because the command is evaluated only once
$x=23
$y=x
$print x
x
The above example returns x as an output and not its value. Hence eval command is to be used.
$x=23
$y=x
$print eval \$$Y
23
When the eval command is executed, it first evaluates $y, which generates the string value $x. The second evaluation then evaluates the variable $x, which produces the correct effect, the printing of the variable stored in y.
Command execution is carried out in six sequential steps. The six execution steps are recursive. This means that when the shell performs the third step, command substitution, the six steps are followed for the command inside the dollar-parentheses.
1. Command Parsing: The shell first parses the command into words In this step, it uses whitespaces as delimiters between the words. It also replaces sequences of two or more spaces or tabs with a single space.
2 Variable Evaluation: After completely parsing the command, the shell looks for variable names (unquoted words beginning with a dollar sign) When a variable name is found, its value replaces the variable name.
3. Command Substitution: The shell then looks for a command substitution. If found, the command is executed and its output string replaces the command, the dollar sign, and the parentheses.
4. Redirection: At this point, the shell checks the command for redirected files. Each redirected file is verified by opening it.
5. Wildcard Expansion: When filenames contain wildcards, the shell expands and replaces them with their matching filenames. This step creates a file list
6. Path Determination: In this last step, the shell uses the PATH variable to locate the directory containing the command code. The command is now ready for execution
Example: Look at the cat command. To show the whitespace characters, we use A to represent a space and to represent a tab. $cat →→$var→→→report*1> file3→2>file4
$ cat fileA fileB fileC report1 report2 1> file3 2> file4 f. In the last step, the shell finds the /bin directory in the PATH variable. completes the command as in the next example: $ /bin/cat fileA fileB fileC report1 report2 1> file3 2> file4
The cat utility is then called with five arguments and the names of the two files
Sequences: If we enter a series of simple commands or pipelines separated by semicolons the shell will execute them in sequence, from left to right. This facility is useful for type ahead (and think-ahead) addicts who like to specify an entire sequence of actions at once Example: $ date; pwd; Is …..execute three commands in sequence. Mon Feb 2 00:11:10 CST 1998 /home/glass/wild a.c b.c cc.c dir1 dir2 $_ Each command in a sequence may be individually I/O redirected, as shown in the following Example: S date > date.txt; Is: pwd > pwd.txt a.c b.c cc.c date.txt dirl dir2
Grouping Commands: Commands may be grouped by placing them between parentheses, which causes them to be executed by a child shell (subshell). The commands a given group share the same standard input, standard output and standard error channels, and the group may be redirected and piped as if it were a simple command. Examples: $ date; Is; pwd » out.txt …execute a sequence Men Feb 2 00:33:12 CST 1998 …output from date a.c b.c …output from Is $ cat out.txt …only pwd was redirected /home/glass $(date; Is; pwd) > out.txt …group and the redirect $cat out.txt …all output was redirected Mon Feb 2 00:33:28 CST 1998 a.c b.c /home/glass $_ |
The Korn shell has two different decision making statements that allows us to choose between different alternatives. The first, the if then - else statement, examines the data and chooses between two alternatives. For this reason, it is sometimes referred to as a two way selection. The second, the case statement, selects one of several paths by matching patterns to different strings.
if - then - else statement : Every language has some variation of the if-then-else statement The only difference between them is what keywords are required by their syntax. The shell evaluates the exit status from the command following fi. When the exit status is 0, then the set of commands is executed. When the exit status is 1, the else set of commands is executed.
Syntax: if command then command command else command
command fi
Example: Program to look at the time of day and print an appropriate greeting, such as "good morning" or "good evening.
#!/bin/ksh # Script : gday.scr hour=$(date | cut-c 12-13) if (( hour <= 18)) then print Good Morning else print Good Evening fi $gday.scr Output: Good Evening
if without else : Often we make a test that requires action only if the test is true. No action is required if the test is false. In this case, we need a then statement without a matching else. When there is no false action, we simply omit the else(false) portion of the command. Syntax: If command then command command fi
Example: Program to determine whether a file exists and is readable. If it is, we cat the file. If the file doesn't exist, we do nothing # Script: Ifnoelse.scr If [[ -r $1]] then cat $1 fi $ifnoelse.scr file1 Output: This is file1
else without if : Although we can have an if-then-else statement without an else action, we cannot have one without a then action When there are no true actions in the if - then - else, we use what is called the null command for the true action. The null command is a colon (:). It does nothing but satisfy the requirement for a command in the then action. Syntax: if command then : else command command fi
Nested if Statements: Each branch in the if-then-else statement can be any command including another if-then-else statement. When an if-then-else statement is found in either the true or false branch of an if-then else command it is called a nested if. This type of nesting is so common that a compact format, in which the if and the else are combined into a word called elif. While either the true or false action can be nested, it is more commonly the false action. Example: Program to grade a student according to the score scored following conditions. if (( score >=90) then grade=A elif ((score >=80)) then grade=B elif ((score >=70)) then grade=C elif ((score >=60) then grade=D else grade=F fi |
case statement: The Korn shell implements multiway selection with the case statement. Given a string and a list of pattern alternatives, the case statement matches the string against each of the patterns in sequence. The first pattern that matches the string gets the action. If no patterns match, the case statement continues with the next command.
|
Figure 4
The case statement contains the string that is evaluated. It ends with an end case token, which is esac (case spelled backward). Between the start and end case statements is the pattern list. For every pattern that needs to be tested a separate pattern is defined in the pattern list. The pattern ends with a closing parenthesis Associated with each pattern is one of more commands. The commands follow the normal rules for commands with the addition that the last command must end in two semicolons. The last action in the pattern list is usually the wildcard asterisk, making it the default if none of the other cases match.
In a command-controlled loop, the execution of a command determines whether the loop body executes or not. There are two command controlled loops in the Korn shell: The while loop and the until loop.
1. while loop: The while loop is a basic command-controlled loop. It begins with while, which contains the loop command and loops as long as the command’s exit status is true (zero). When the exit status becomes false (nonzero) the loop terminates.
Syntax:
Figure 5
Figure 6
2. until loop: The until loop works just like the while loop, except that it loops as long as the exit status of the command is false. In this sense, it is the complex of the while loop
Syntax:
Figure 7
Example: #!/bin/ksh # script untl a=0 until [ $a -ge 101 do echo $a a= ‘expr $a+1’ done $ ksh untl 0 1 2 3 4 5 6 7 8 9 10 Repeat loop: The repeat loop is a very simple loop that executes one command specified number of times. It requires two parameters: the number of times to loop and a single command to be executed. The command must be simple; that is, it cannot have a pipe or other complex construct. Example: Script to demonstrate repeat loop #1/bin/ksh/ -f #Script : loopRepeat.scr set looper = 5 repeat $looper echo Hello %loopRepeat.scr Output: Hello Hello Hello Hello Hello |
In a list-controlled loop, there is a control list. The number of elements in the list controls the number of iterations. If the control list contains five elements, the body of the loop is executed five times, if the control list contains ten elements, the body of the loop is executed ten times.
- The for-in Loop: The first list-controlled loop in the Korn shell is the for-in loop. The list can be any type of string, for example, it can be words, lines, sentences, or a file. In each iteration, the next element in list is moved to variable and processed.
Syntax:
Figure 8
2. select loop: The second Korn shell list-controlled loop is the select loop. The select loop is a special loop designed to create menus. A menu is a list of opti displayed on the monitor. The user selects one of the menu options, which is the processed by the script. The format of the select loop is similar to the for-in loop. It begins with the keyword select followed by a variable and a list of strings:
$ select variable in list
Following the select command is the loop body. The user's actual response is stored in the shell REPLY variable. The list text that corresponds to the user's response is stored in the variable specified in the select command.
There are two other statements related to loops: break and continue:
1. Break Statement: The break statement immediately exits from the loop (but not from the script). Processing continues with the first command after the loop. The break statement is generally an action in a selection statement such as an if-then- else or a case
2. Continue Statement: The continue statement causes the loop to ignore the rest of the body commands and immediately transfers control to the test command. If the loop is not complete, the next iteration begins.
Figure 8
Whenever we write a script we must test it. Often multiple tests are necessary. Sometimes the tests don't deliver the expected results. In these cases, we need to debug the script. There are two Korn shell options that we can use to help debug scripts: the verbosity (verbose) option, and the execute trace (xtrace) option.
The verbose option prints each statement that is syntactically correct and displays an error message if it is wrong. Script output, if any, is generated.
The xtrace option prints each command, preceded by a plus (+) sign, before it is executed. It also replaces the value of each variable accessed in the statement.
For example, in the statement y= $x, the $x is replaced with the actual variable value at the time the statement is executed. If the variable x contained 13, the display would be y=13. In a similar manner, expression values and test values are displayed. Combining the two options allows us to see the command first and then see it with a plus sign and all references to variables replaced by their values.
We can use these debug commands in two ways: include the options in the script and call the script with them.
$ cat dbugoptstV set -o verbose x=5 ((y = x+2)) If (( y == 10 )) then print \$y contains 10 else print \$y contains $y not 10 fi
while ((x !=0)) do print counting down : \$x is $x ((x =x - 1)) done $ ksh dbugoptstv x=5 (y = x+2)) if(y== 10 )) then print \$y contains 10 else print \$y contains $y not 10 fi $y contains 7 not 10 while ((x!=0)) do print counting down : \$x is $x ((x = x- 1)) done counting down : $x is 5 counting down : $x is 4 counting down : $x is 3 counting down : $x is 2 counting down : $x is 1
When the debug option is included in the script, we must edit it to remove the set command when we complete the debug sessions. We can avoid this extra step if we include the options on the command line. This requires that we invoke the Korn shell in the command. $ cat dbugoptstV set -o verbose x=5 ((y=x+2)) if (( y == 10 )) then print \$y contains 10 else print \$y contains $y not 10 fi
while ((x !=0)) do print counting down : \$x is $x ((x = x - 1)) done
$ ksh - xtrace dbugoptstv + x=5 + (( y = x+2 )) + ((y == 10 )) + print $y contains 7 not 10 $y contains 7 not 10 + ((x != 0 )) + print Counting down: $x is 5 Counting down: $x is 5 + (( x = x - 1 )) + ((x != 0)) + print Counting down: $x is 4 Counting down: $x is 4 + (( x = x - 1 )) + ((x != 0 )) + print Counting down: $x is 3 Counting down: $x is 3 + ((x = x-1 )) + ((x != 0 )) + print Counting down: $x is 2 Counting down: $x is 2 + ((x =x-1)) + ((x != 0 )) + print Counting down: $x is 1 Counting down: $x is 1 + ((x = x-1 )) +(( x != 0)) |
echo "Enter the number: read fact ans=1 counter=0 while [ $fact -ne $counter ] do counter='expr $counter + 1’ ans='expr $ans \* $counter’ done echo "The factorial of a given number is $ans" Output: Enter the number: 5 The factorial of a given number is 120 2. Write a korn script to generate Fibonacci series upto 10 terms Scat fibo.ksh clear echo "How many number of terms to be generated ?" read n x=0 y=1 i=2 echo "Fibonacci Series up to $n terms :" echo "$x" echo "$y" while [ $i -lt $n ] do i='expr $i+1’ z='expr $x + $y’ echo "$z" x=$y y=$z done $sh fibo.ksh How many number of terms to be generated ? 7 Fibonacci Series up to $n terms: 0 1 2 3 5 8 13 21
3. Write a korn script to check whether the given number is prime or not. $cat prim.ksh echo "Enter a number: " read num i=2 f=0 while [ $i-le 'expr $num / 2’] do if ['expr $num % $i' -eq 0] then f=1 fi i='expr $i +1’ done If [ $f -eq 1] then echo "The number is composite" else echo "The number is Prime" fi $sh prim.ksh Enter a number: 13 The number is Prime
4. Write a kom shell script to create a simple calculator for addition, subtraction multiplication and division using select loop. print *************MENU*************** select ch in ADD SUB MUL DIV EXIT do case $ch in ADD) print "Enter First Number: read fn print "Enter Second Number:” read sn res-'echo "$fn + $sn"|bc’ print "The addition of $fn and $sn is $res";; SUB) print "Enter First Number :” read fn print "Enter Second Number: " read sn res=’echo "$fn - $sn"|bc’ print "The subtraction of $in and $sn is $res";; MUL) print "Enter First Number :" read fn print "Enter Second Number:” read sn res= ‘echo "$fn * $sn|bc’ print "The multiplication of $fn and $sn is Sres";; DIV) print "Enter First Number:” read fn print "Enter Second Number :” read sn res='echo "scale=2;$fn / $sn|bc’ print "The division of $fn and $sn is $res";; EXIT) break;; Esac Done 5. Write a korn shell script which accept an integer number as input and find the sum of its digit.
print "Enter a Number:" read num sum=0 while [ $num -gt 0] do r='expr $num % 10’ num='expr $num / 10’ sum='expr $sum + $r’ done print "The sum of its digit of a input Number is : $sum" 6. Write a shell script to reverse the digits of a gives number. echo "Enter the number" read n sd=0 rev=0 while [ $n -gt 0 ]; do sd=$((n % 10 )) rev=$(( $rev *10 + $sd )) n=${{ $n/ 10 )) done echo "Reverse of entered digit is $rev"
7. Write a script to print the word hello five times using for loop. #1/bin/ksh # Script: loopFor.scr for I in 1 2 3 4 5 do print $i hello done $loopFor.scr Output: 1 hello 2 hello 3 hello 4 hello 5 hello
8. Script to display a message in language of your choice. #!/bin/ksh # Script: selectloop.scr print " This script displays a message in language of your choice" PS3="Enter your selection :" Select choice in English Spanish French Quit do case $choice in English) print "thank you";; Spanish) print "gracias";; French) print "merci";; Quit) break;; *)print $REPLY is an Invalid choice please try esac done $selectioop.scr Output: This script displays a message in the language of your choice 1) English 2) Spanish 3) French 4) Quit 9. Program to read lines from keyboard. It adds the number entered and then iterates using while loop. #!/bin/ksh # Script :loopAdd.scr print "This utility adds numbers entered from the" print "keyboard. When all numbers have been entered," print "key ^d(eof) to see the total.\n" sum=0; print "Enter a number: \c" while read data do (( sum= sum + data)) print "enter next number: \c"
done print "\n Sum Is :"$sum $loopAdd.scr Output: This utility adds numbers entered from the keyboard. When all numbers have been entered, key ^d(eof) to see the total. Enter a number:2 enter next number: 4 enter next number:6 enter next number:^d Sum is:12
10. Program to write a script to print the spelling of a digit. #!/bin/ksh # Script: caseDigit.scr print "Enter a digit: \c" read digit print "\n you entered $digit. It is spelled : \c" case $digit in 0) print zero.;; 1) print one.;; 2) print two.;; 3) print three.;; 4) print four.;; 5) print five.;; 6) print six.;; 7) print seven.;; 8) print eight.;; 9) print nine.;; *) print not a digit.,; esac $caseDigit.scr Output: Enter a digit:3 you entered 3. It is spelled: three |
References
- Sumitabha Das: UNIX – Concepts and Applications, 4th Edition, Tata McGraw Hill, 2006.
- Behrouz A. Forouzan and Richard F. Gilberg: UNIX and Shell Programming, Cengage Learning, 2005.
- M.G. Venkateshmurthy: UNIX & Shell Programming, Pearson Education, 2005.