|
Shell programming and simple menus - part 1The anatomy of a menu shell script |
Learning to build a menu can quickly become an interesting exercise in
shell programming. In this first of two columns on building menus, we
show different ways of displaying prompts, how to define a function,
and how to use case-esac
. We then put everything together
in a sample shell script menu and explain it piece by piece.
(2,900 words)
Mail this article to a friend |
A menu system is an almost mandatory add-on to any Unix system in the real world. In saying "real world" Unix system, I mean one that doesn't involve sitting in a dark room hunched over a glowing terminal trying to determine the next highest prime number.
Commercial menu systems involve more than a simple prompt that dispatches to some program based on a user selection. But often a simple approach will get the job done. While I was creating EZMENU for Unix, one customer required just such a simple solution.
The menu had to:
The design of the menu is simple, and it provides an excellent vehicle to learn some shell programming tricks. The logic for a menu can be described in the following simple steps:
echo "Please enter 1 to select Accounts Receivable"
or indirectly using a variable as in:
amenu="Please enter 1 to select Accounts Receivable" echo $amenuA menu pick can be collected from the user by using the read command which will read input from the keyboard as in:
echo "Please enter your choice" read answer
|
|
|
|
Defining functions
Another important feature of the shell (sh or ksh) is the ability to define
a function. A shell function is a collection of one or more shell commands
that are given a function name. A function can be executed by issuing the
name of the function in the shell script as if it were a Unix command.
However, a function must be defined before it can be executed. To define a
function, give it a name followed by an open and close parentheses,
followed by opening and closing curly braces. Within the curly braces place
the commands to be executed.
The following lines define a function
pagedir
and then execute it. The function executes
an ls -l
command and then pipes
the results through more
to create a paging display.
#!/bin/sh # Define a paged directory listing function pagedir () { ls -l|more ; } # and then execute it pagedir
Repeating a command or set of commands can be done by enclosing the commands within a while-do-done command.
In the following example the shell logic loops until the user enters something other than "y."
#!/bin/sh answer=y while [ $answer = y ] do echo "Hello" echo "go again?" read answer done
Shell scripts also allow for a case-select type construction, case-esac
that executes one of several choices based on a variable containing one of
a list of values. In the example below the choices are a), b), c), and
finally, *), which stands for anything else.
#!/bin/sh # How to use case-esac echo "Please enter a letter a through c" read answer case $answer in a) echo You chose a;; b) echo You chose b;; c) echo You chose c;; *) echo You did not chose a, b or c;; esac
A case-esac
choice can also be set up to allow the user to
enter the upper or lower case versions. In the example below the choices
are a|A), b|B), c|C), or *) which stand for a or A (a|A), b or B (b|B),
c or C (c|C), or anything else.
# How to use case-esac with upper or lower case. echo "Please enter a letter a through c" read answer case $answer in a|A) echo You chose a;; b|B) echo You chose b;; c|C) echo You chose c;; *) echo You did not chose a, b or c;; esac
This set of tools can be used to build a simple shell script menu such as that shown in Listing 1 (below). Listing 1 contains line numbers to the left of each actual line in order to facilitate the explanation of the listing.
This menu allows other programs or shell commands to be launched directly
from the menu. As further items are needed for the menu, a prompt can be
added as emenu
, and the program name or commands can be placed inside the
function definition of epick ()
. The required commands should replace badchoice ()
as the routines to execute.
I chose .mnu as an extension for this script file to indicate that it was a menu, but there is no need for the extension.
Listing 1: Sample shell script menu
1. #!/bin/sh 2. # sample.mnu 3. # A simple script menu under Unix 4. # Main logic starts at MAIN LOGIC 5. # The logo will be displayed at the top of the screen 6. LOGO="Sample Menu" 7. 8. #------------------------------------------------------ 9. # MENU PROMPTS 10. #------------------------------------------------------ 11. # A list of menu prompts to be displayed for the user. 12. # The list can be modified. 13. # In this first list, enter the menu prompt as it should appear 14. # on the screen for each of the letters A - L. In this example 15. # menu pick variables emenu through lmenu are blank as there 16. # are no menu selections for keys E through L. 17. 18. amenu="a. Job Scheduling" ; 19. bmenu="b. Set Standard Defaults " ; 20. cmenu="c. Display Directory Listing " ; 21. dmenu="d Payroll Menu " ; 22. emenu=" " ; 23. fmenu=" " ; 24. gmenu=" " ; 25. hmenu=" " ; 26. imenu=" " ; 27. jmenu=" " ; 28. kmenu=" " ; 29. lmenu=" " ; 30. 31. #------------------------------------------------------ 32. # MENU FUNCTION DEFINITIONS 33. #------------------------------------------------------ 34. 35. # Define a function for invalid menu picks 36. # The function loads an error message into a variable 37. badchoice () { MSG="Invalid Selection ... Please Try Again" ; } 38. 39. # For each prompt displayed above, there is a list of 40. # commands to execute in response to the user picking the 41. # associated letter. 42. # They are defined as functions 43. # apick () through lpick () where 44. # apick () corresponds to the menu 45. # prompt amenu which is selected 46. # selected by pressing a or A. 47. # bpick () corresponds to the menu 48. # prompt bmenu which is selected by 49. # pressing b or B and so on. 50. # Any menu item that is not 51. # assigned a set of commands, is 52. # assigned 53. # the function badchoice () as a default for that pick. 54. # If the user 55. # selects a menu key that is assigned 56. # to badchoice (). This function 57. # causes an error message to be 58. # displayed on the screen. 59. # To add items to this second 60. # list, replace badchoice () 61. # with the commands to run when 62. # that letter is pressed. 63. # The following steps simply define 64. # the functions, but do not cause 65. # any shell program steps to be executed. 66. 67. apick () { sched ; } 68. bpick () { defmnt ; } 69. cpick () { ls -l| more ; echo Press Enter ; read DUMMY ; } 70. dpick () { payroll.mnu ; } 71. epick () { badchoice ; } 72. fpick () { badchoice ; } 73. gpick () { badchoice ; } 74. hpick () { badchoice ; } 75. ipick () { badchoice ; } 76. jpick () { badchoice ; } 77. kpick () { badchoice ; } 78. lpick () { badchoice ; } 79. 80. #------------------------------------------------------ 81. # DISPLAY FUNCTION DEFINITION 82. #------------------------------------------------------ 83. # This function displays the menu. 84. # The routine clears the screen, echoes 85. # the logo and menu prompts 86. # and some additional messages. 87. # Note that this definition does 88. # not cause the function to 89. # be executed yet, it just defines 90. # it ready to be executed. 91. 92. themenu () { 93. # clear the screen 94. clear 95. echo `date` 96. echo 97. echo "\t\t\t" $LOGO 98. echo 99. echo "\t\tPlease Select:" 100. echo 101. echo "\t\t\t" $amenu 102. echo "\t\t\t" $bmenu 103. echo "\t\t\t" $cmenu 104. echo "\t\t\t" $dmenu 105. echo "\t\t\t" $emenu 106. echo "\t\t\t" $fmenu 107. echo "\t\t\t" $gmenu 108. echo "\t\t\t" $hmenu 109. echo "\t\t\t" $imenu 110. echo "\t\t\t" $jmenu 111. echo "\t\t\t" $kmenu 112. echo "\t\t\t" $lmenu 113. echo "\t\t\tx. Exit" 114. echo 115. echo $MSG 116. echo 117. echo Select by pressing the letter and then ENTER ; 118. } 119. 120. #------------------------------------------------------ 121. # MAIN LOGIC 122. #------------------------------------------------------ 123. # Every thing up to this point has been to define 124. # variables or functions. 125. # The program actually starts running here. 126. 127. # Clear out the error message variable 128. MSG= 129. 130. # Repeat the menu over and over 131. # Steps are: 132. # 1. Display the menu 133. # 2. 'read' a line of input from the key board 134. # 3. Clear the error message 135. # 4. Check the answer for a or A or b or B etc. and dispatch 136. # to the appropriate program or function or exit 137. # 5. If the entry was invalid call the badchoice () function 138. # to initialize MSG to an error message 139. # 6. This error message is used when setting up the menu 140. # for a menu pick that is valid but has no command 141. # associated with it. 142. 143. while true 144. do 145. # 1. display the menu 146. themenu 147. 148. # 2. read a line of input from the keyboard 149. read answer 150. 151. # 3. Clear any error message 152. MSG= 153. 154. # 4. Execute one of the defined functions based on the 155. # letter entered by the user. 156. 157. # 5. If the choice was E through L, the pre-defined 158. # function for that pick will execute badchoice () 159. # which loads an error message into MSG 160. 161. case $answer in 162. a|A) apick;; 163. b|B) bpick;; 164. c|C) cpick;; 165. d|D) dpick;; 166. e|E) epick;; 167. f|F) fpick;; 168. g|G) gpick;; 169. h|H) hpick;; 170. i|I) ipick;; 171. j|J) jpick;; 172. k|K) kpick;; 173. l|L) lpick;; 174. 175. # If the user selects =91x=92 to exit then break out 176. # of this loop 177. x|X) break;; 178. 179. # 6. If the entry was invalid call the badchoice function 180. # to initialize MSG to an error message 181. *) badchoice;; 182. 183. esac 184. 185. # Do it again until the user enters =91x=92. 186. done
What the menu shell script does
Lines 1 through 30 contain the "data" for the menu system. Line 6 contains
a menu name or logo that is displayed at the top of the menu. Lines 18
through 29 include the variables amenu
through lmenu
, containing the prompts for 12 lines of menu options. In Listing 1 prompt values are
defined for amenu
through dmenu
. The variables emenu
through lmenu
are left
blank. To create your own custom menu you would modify these value to
display up to 12 lines of menu options.
Lines 31 through 119 contain function definitions used by the script. In all of these lines of code, no actual program steps are performed. Instead the script builds the functions that will be used in the main logic of the program.
Line 35 contains a definition for a badchoice ()
function.
This is a simple
function that is used by the menu system whenever the user:
badchoice ()
function is very simple. It loads a
variable with an error message.
Lines 67 through 78 contain the definitions of 12 functions,
apick ()
through lpick ()
.
These functions are the commands to be executed
when a user makes a menu pick. For epick
through
lpick
, the command is to
call the badchoice ()
function.
The apick ()
function at line 67 starts the program, sched, a job
scheduling program.
The bpick ()
function at line 68 starts defmnt, another program for
maintaining some sort of defaults.
The cpick ()
function at line 69 invokes multiple commands, ls -l| more
followed by echo Press Enter
followed by
read DUMMY
. These separate commands are all captured in a single line
of semi-colon separated commands as:
{ls -l| more ; echo Press Enter ; read DUMMY ; }The
dpick ()
function at line 70 runs another menu script titled
payroll.mnu.
These definitions of apick ()
through lpick ()
can be modified along with the
prompts at lines 18 through 29 to create a custom menu. The remainder of
the menu would be the same for all shell script menus.
At lines 92 through 118 a long function, themenu ()
, is defined. This
function is used to display the menu on the screen. It clears the screen,
echoes the date, the menu name ($LOGO), the 12 menu picks amenu
through
lmenu
, an exit prompt, a $MSG variable, and a few other cosmetics to the
screen.
So far nothing has actually happened in the program. To this point it consists of definitions of variables and functions to be used in the program.
The program itself appears at lines 120 through 186 at the end of the script beginning at MAIN LOGIC.
The program is one line of initialization of the MSG variable at line 128 and an infinite loop from lines 143 through 186.
Inside the loop the program steps are:
badchoice ()
, call the badchoice ()
function to
initialize the MSG variable to an error message.
After you have created sample.mnu be sure to make it executable by typing:
chmod a+x sample.mnuThe script displays a simple menu as in Figure 1 and asks the user to enter a single character and press enter to execute the request.
Figure 1 - The screen produced by sample.mnu
------------------------------------------------------------------------ Fri May 30 14:30:18 PDT 1997 Sample Menu Please Select: a. Job Scheduling b. Set Standard Defaults c. Display Directory Listing d Payroll Menu x. Exit Invalid Selection Please try again Select by pressing the letter and then ENTER ------------------------------------------------------------------------If the user enters an invalid letter or selects a valid letter that has not yet had a selection attached to it, an
Invalid Selection
message is
displayed. An example of this message is already on the screen in line 21
as shown in Figure 1.
This provides a simple menu that can be maintained by editing the prompts at lines 18 through 29 and the picks at lines 67 through 78.
In the next installment we'll take this simple menu concept another few steps and learn some more about shell programming.
|
Resources
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.
If you have technical problems with this magazine, contact webmaster@sunworld.com
URL: http://www.sunworld.com/swol-07-1997/swol-07-unix101.html
Last modified: