Unix 101 by Mo Budlong

Quick lessons on shell programming

How to start writing your own shell scripts

September  1997
[Next story]
[Table of Contents]
Sun's Site

The various Unix shells can be used for programming as well as simply interpreting commands. This month we get you started with shell programming, showing you first how to define shell functions and then how to tap into their power by integrating them into shell scripts. (2,000 words)

Mail this
article to
a friend
The Unix shell in its various incarnations, the Bourne Shell (sh), the Korn Shell (ksh), the C Shell (csh), the Bourne Again Shell (bash), is a powerful programming tool.

Although most people are familiar with the ability of the shell to interpret commands as they are typed in at the terminal, many are not familiar with its ability to execute programs or shell scripts. Even more people are not familiar with all of the tools available in a shell script.

The tools that can be used to create a shell script program are all built into the shell -- whichever one you are using -- but they are rarely used in single command lines that are typed in at the terminal.

Functions are a powerful feature of shell programming for the the Bourne Shell and its derivatives, Korn Shell and bash.

For these exercises type ksh to start the Korn shell and press Enter. If an error occurs then type sh to start the Bourne shell and press Enter.

A function is a single command that can be defined to stand in for one or more Unix commands. Using a function involves two steps: defining the function and then invoking or executing the function.

The first safe step to take is to check if the function name that you intend to use is currently in use. In this case you are going to create a function named "greetings." Type greetings and press Enter. You should receive a message that greetings could not be found. If this is not the case, then select another command such as "hi_there" until you find one that is not found:

ksh: greetings: not found 

To define a function give the function a standard Unix-type name, in this case greetings, followed by the definition of the function. There are two different versions of the syntax for defining a function. In the example below, either command will define a function named greetings that prints "Hello there" on the screen:

$ function greetings { echo Hello there ; }
$ greetings () { echo Hello there ; }

Type in either command, and you will notice that nothing appears to
happen. All you have done is define the function, but you have not
yet executed it. To execute the function, type its name just as you
would a standard Unix command. The function will execute:

$ greetings
Hello there

Expand on this a bit and define the function to include displaying the environment variable containing the user I.D.:

$ greetings () { echo Hello there $LOGNAME ; } 
Now when you type greetings, the message is more personalized.
$ greetings
Hello there mjb

A function may be defined to execute multiple commands by separating the commands with a semi-colon or a newline. The examples below both define a function named "whatdo" that will list processes started by the current user. The ps -ef command is piped in grep to search for lines containing the user id ($LOGNAME) and the result is piped through more. At the end of the display "Press Enter" is displayed and a dummy variable is read from the keyboard until the user presses Enter. These examples use the two different syntaxes for defining a function. Note that in the second version, a newline is used to replace each semi-colon, and after each new line the continuation prompt (>) is displayed:

$ whatdo () { ps -ef|grep $LOGNAME|more ; echo Press Enter ; read x ; }

$ function whatdo {
> ps -ef|grep $LOGNAME|more
> echo Press Enter
> read x
> }

Now type whatdo, and you will see a display of your activities:

$ whatdo
   mjb   260     1  7  Jul 31   01      0:04 -ksh
   mjb   261     1  0  Jul 31   02      0:01 -ksh
   mjb  2293     1  0  10:31:37 03      0:01 -ksh
   mjb  2313   260  7  10:45:06 01      0:00  ps -ef
   mjb  2314   260  7  10:45:06 01      0:00  grep mjb
   mjb  2315   260  7  10:45:06 01      0:00  more
Press Enter


Integrating functions into shell scripts
While functions are fine on the command line, their true power comes about in shell scripts.

First some rules about shell scripts. Ensure that any shell script you create will run using /bin/sh or /bin/ksh by starting the shell script in one of two ways:

  1. Always start with a blank line.
  2. Always start with the line #! /bin/sh or #! /bin/ksh

The first method will work on older versions of Unix. The second method has been supported on many versions of Unix for several years now.

In the following examples, I will use the second version.

In the examples I have shown you so far, functions are used to create a sort of alias for one or more other commands. Within shell scripts, functions are used to tidy up the script so that it is more readable and to avoid having to repeat the same logic over and over. It frequently makes the logic of a long shell script easier to follow.

In Listing 1 I have added line numbers to simplify the explanation. You can type this in as simpmenu using vi or some other editor. Then change the execution status with chmod a+x simpmenu.

At lines 4 through 20 a long function named amenu() is defined. This function clears the screen and displays a set of prompts in a menu format. Lines 24 through 27 define a PressEnter() function that asks the user to press ENTER and then waits for a key press.

Lines 29 through 44 define functions that are to be used or called in response to each menu pick. Note that each of these three functions uses a call to PressEnter within the body of the function. This ability to use a function inside another function makes programming much easier. Without this ability, the logic of the PressEnter function would have to be fully typed in each time within the body of the three main functions that are executed by the menu.

Up until line 63, no actual program has been run. If the shell script stopped at this point, nothing would have happened. At line 63 the program begins with a permanent loop (while true) that runs to line 85. The menu is displayed by calling the function amenu at line 66. The read command is used to read the variable answer at line 69. At line 74, a case statement tests the value in $answer and executes one of the three defined functions based on the user's choice or issues a break command that breaks out of the permanent loop.

Listing 1: A simple demonstration of functions

1. #! /bin/ksh
2. # simpmenu, A very simple menu
4. # amenu() defines a function to display a simple menu
5. amenu () {
6. # clear the screen
7. clear
8. echo `date`
9. echo
10. echo "\t\t\tMy Personal Menu"
11. echo
12. echo "\t\tPlease Select:"
13. echo
14. echo "\t\t\t 1. Directory display"
15. echo "\t\t\t 2. Current Activity"
16. echo "\t\t\t 3. Who is logged on"
17. echo "\t\t\t"
18. echo "\t\t\t 0. Exit"
19. echo Select by pressing a number and then ENTER ;
20. }
22. # A function that asks the user to press enter
23. # and waits for the ENTER Key
24. PressEnter () {
25. echo Press Enter
26. read x
27. }
29. # A function for each of the menu picks
30. DirectoryDisplay () {
31. ls -l|more
32. PressEnter
33. }
35. CurrentActivity ()
36. {
37. ps -ef|more
38. PressEnter
39. }
41. WhoIsLoggedOn () {
42. who|more
43. PressEnter
44. }
46. # The main logic for the program displays the menu
47. # gets the users entry and initiates the activity
48. #------------------------------------------------------
50. #------------------------------------------------------
51. # Every thing up to this point has
52. # just defined functions
53. # The program actually starts running here.
55. # Repeat the menu over and over
56. # Steps are:
57. # 1. Display the menu
58. # 2. 'read' a line of input from the key board
59. # 3. Check the answer for 1, 2, 3 or 0 and dispatch
60. #    to the appropriate function or exit
61. # 4  Repeat until 0 is entered
63. while  true
64. do
65. # 1. display the menu
66.   amenu
68. # 2. read a line of input from the keyboard
69.   read answer
71. # 3. Execute one of the defined functions based on the
72. #    number entered by the user.
74.   case $answer in
75.       1) DirectoryDisplay ;;
76.       2) CurrentActivity ;;
77.       3) WhoIsLoggedOn ;;
79. #      If the user selects 0 to exit then break out
80. #      of this loop
81.       0) break ;;
82.   esac
84. #     Do it again until the user enters 0.
85. done
87. # Clear the screen on the way out
88. clear

Listing 2 is the same activity but without functions. It is much harder to read and contains a lot of duplicate code.

Listing 2: The non function version of listing 1

1. #! /bin/ksh
2. # simpmenu, A very simple menu
5. # The main logic for the program displays the menu
6. # gets the users entry and initiates the activity
7. #------------------------------------------------------
9. #------------------------------------------------------
11. # Repeat the menu over and over
12. # Steps are:
13. # 1. Display the menu
14. # 2. 'read' a line of input from the key board
15. # 3. Check the answer for 1, 2, 3 or 0 and dispatch
16. #    to the appropriate function or exit
17. # 4  Repeat until 0 is entered
19. while  true
20. do
21. # 1. display the menu
22. # clear the screen
23. clear
24. echo `date`
25. echo
26. echo "\t\t\tMy personal menu"
27. echo
28. echo "\t\tPlease Select:"
29. echo
30. echo "\t\t\t 1. Directory display"
31. echo "\t\t\t 2. Current Activity"
32. echo "\t\t\t 3. Who is logged on"
33. echo "\t\t\t"
34. echo "\t\t\t 0. Exit"
35. echo Select by pressing a number and then ENTER 
37. # 2. read a line of input from the keyboard
38.   read answer
40. # 3. Execute commands based on the
41. #    number entered by the user.
43.   case $answer in
44.       1) 
45.             ls -l|more
46.             echo Press Enter
47.             read x ;;
48.       2) 
49.             ps -ef|more
50.             echo Press Enter
51.             read x ;;
52.       3) 
53.             who|more
54.             echo Press Enter
55.             read x ;;
57. #      If the user selects 0 to exit then break out
58. #      of this loop
59.       0) break ;;
60.   esac
62. #     Do it again until the user enters 0.
63. done
65. # Clear the screen on the way out
66. clear

Use functions to tidy up long shell scripts and you will be taking advantage of one of the powerful features of the shell programming language.


About the author
Mo Budlong is president of King Computer Services, Inc. and has been involved in Unix development on Sun and other platforms for over 15 years. King Computer Services, Inc. specializes in Unix and Client/Server consulting and training and currently publishes the COBOL Just In Time Course, a crash COBOL course to train staff for the Year 2000 problem. Reach Mo at mo.budlong@sunworld.com.

What did you think of this article?
-Very worth reading
-Worth reading
-Not worth reading
-Too long
-Just right
-Too short
-Too technical
-Just right
-Not technical enough

[Table of Contents]
Sun's Site
[Next story]
Sun's Site

[(c) Copyright  Web Publishing Inc., and IDG Communication company]

If you have technical problems with this magazine, contact webmaster@sunworld.com

URL: http://www.sunworld.com/swol-09-1997/swol-09-unix101.html
Last modified: