Korn Shell select Loop

The select statement in the Korn shell creates a menu. This construct is for the Korn shell only. The syntax for creating a menu is:

select var in list
do
    statement1
    ...       
    statementN
done

The variables var and list follow the same syntactic rules used in the for loop (although the operation of the select loop is substantially different). If the list contains metacharacters, the metacharacters are expanded into file names.

The elements in the list are the menu choices presented to the user. The Korn shell automatically numbers each menu choice (starting with 1). The user must enter the number corresponding to the user’s choice for the input to be valid.

Although you can use any statements within the select loop, the case statement is most often used to match the choice selected by the user and to take certain actions depending on that choice.

The input the user provides is saved in the REPLY variable. If the user does not enter any input except for pressing the Return key, then the REPLY variable is set to the null string, and the shell redisplays the menu choices.

The select loop is exited when the user types the end-of-file (EOF) character, which is Control-D on most systems.

The PS3 Reserved Variable

After displaying the list of menu choices for a user, the shell prints a prompt and waits for user input. The prompt value is the value of the PS3 variable. You can set this variable to any value, but it helps if the value makes sense with regard to the choices that are presented to the user.

Sometimes a script produces so much output — between the time the menu list first displays to when the menu prompt is displayed — that a user is no longer able to see (or remember) the menu choices. To redisplay menu choices, a user presses the Return key in response to the menu prompt.

The select syntax creates a loop. A user is repeatedly presented with menu choices followed by a prompt (the value of the PS3 variable). The select loop is exited when a user types the EOF character for the system as the response to the menu prompt.

The default value of the PS3 variable in the Korn shell is #?. Therefore, if you fail to set the PS3 variable, the system uses the string #? as the prompt and then waits for user input. If this happens, the user might not know that the script is waiting for input.

Example of Using a select Loop

The following script gives users five fruit choices and then prompts for their fruit choice. A case statement is used in the select loop to take appropriate action on the choice selected by the user. The default case, the * pattern, matches any input by the user that is not one of the numbers of the choices on the menu.

The script then executes. Several valid choices and some invalid choices are shown to illustrate how the select loop works.

$ cat menu.ksh 
#!/bin/ksh

# Script name: menu.ksh

PS3="Enter the number for your fruit choice: "

select fruit in apple orange banana peach pear 
do
    case $fruit in
    apple) 
        print "An apple has 80 calories."                
        ;;

    orange)
        print "An orange has 65 calories."                
        ;;

    banana)
        print "A banana has 100 calories."                
        ;;

    peach)
        print "A peach has 38 calories."                
        ;;

    pear)
        print "A pear has 100 calories."                
        ;;

    *) 
        print "Please try again. Use ’1’-’5’"
        ;; 
esac
done
$ ./menu.ksh 
1) apple 
2) orange 
3) banana 
4) peach 
5) pear 
Enter the number for your fruit choice: 3 
A banana has 100 calories. 
Enter the number for your fruit choice: 7
Please try again. Use ’1’-’5’ 
Enter the number for your fruit choice: apple 
Please try again. Use ’1’-’5’ 
Enter the number for your fruit choice: 1 
An apple has 80 calories. 
Enter the number for your fruit choice: ^d

Exiting the select Loop

Users can exit the select loop at any time by entering the EOF character on their system; however, unless users know this or you include a message explaining this in your menu prompt, users can get stuck in the select loop.

Include a string in your menu choices to help users exit the menu. The string could simply say Quit Menu. Then the action in the case statement for this menu choice would be the break statement. The break statement exits the select loop, and execution of the script moves to the first statement following the done statement in the select/do/done syntax. If there are no statements following the done statement, the script terminates.

$ cat menu1.ksh 
#!/bin/ksh

# Script name: menu1.ksh

PS3="Enter the number for your fruit choice: "

select fruit in apple orange banana peach pear "Quit Menu" 
do
    case $fruit in
        apple)
            print "An apple has 80 calories." 
            ;;

        orange)
            print "An orange has 65 calories." 
            ;;

        banana) 
            print "A banana has 100 calories." 
            ;;

        peach) 
            print "A peach has 38 calories."
            ;;

        pear)
            print "A pear has 100 calories."
            ;;

        "Quit Menu")
            break 
            ;;

        *) 
            print "You did not enter a correct choice." 
            ;; 
    esac 
done
$ ./menu1.ksh 
1) apple 
2) orange 
3) banana 
4) peach 
5) pear 
6) Quit 
Menu Enter the number for your fruit choice: 3 
A banana has 100 calories. 
Enter the number for your fruit choice: 6

Submenus

The shell allows any statement within the select loop to be another select loop. This enables you to create a menu that has one or more submenus. You usually include a break statement in an action for one or more choices on a submenu to exit a submenu loop and return to an outer menu loop.

Because the PS3 variable is also used for the prompt in any submenu, be careful when moving from one menu to another to reset this variable to the prompt for the menu to which you are moving. An example illustrating a submenu and the resetting of the PS3 variable is provided next.

Example of Using Submenus

The following submenu.ksh example script first creates two variables, main_prompt and dessert_prompt, to hold the prompts for the main menu and the dessert submenu, respectively.

The select loop for the main menu is exited when the user chooses Order Completed, at which time the script prints the message Enjoy your meal. When the user selects the main menu choice dessert, a submenu appears, asking the user to input the number for the dessert choice.

In the case statement for the select loop for the dessert menu, the break statement is used for each menu choice. (The default choice does not use the break statement because you want the user to reenter a dessert choice.) This exits the dessert menu. Then the menu prompt resets to the value of the main_prompt variable, and control returns to the main (outer) select loop.

All print statements use single quotes so that the $ in the prices is printed. Also, because of formatting in this course book, several lines in the following script wrap.

$ cat submenu.ksh 
#!/bin/ksh

# Script name: submenu.ksh

main_prompt="Main Menu: What would you like to order? " 
dessert_menu="Enter number for dessert choice: " 
PS3=$main_prompt

select order in "broasted chicken" "prime rib" "stuffed lobster" dessert "Order Completed" 
do 
case $order in 
    "broasted chicken") 
    print 'Broasted chicken with baked potato, rolls, and salad is $14.95.'
    ;; 

    "prime rib") 
    print 'Prime rib with baked potato, rolls, and fresh vegetable is $17.95.'
    ;; 

    "stuffed lobster") 
    print 'Stuffed lobster with rice pilaf, rolls, and salad is $15.95.'
    ;; 

    dessert) 
        PS3=$dessert_menu 
        select dessert in "apple pie" "sherbet" "fudge cake" "carrot cake" 
        do 
            case $dessert in 
                "apple pie") 
                print 'Fresh baked apple pie is $2.95.' 
                break
                ;; 

                "sherbet") 
                print 'Orange sherbet is $1.25.' 
                break
                ;; 

                "fudge cake") 
                print 'Triple layer fudge cake is $3.95.' 
                break
                ;; 

                "carrot cake") 
                print 'Carrot cake is $2.95.' 
                break;; 

                *) 
                print 'Not a dessert choice.'
                ;; 
            esac 
        done 
        PS3=$main_prompt
        ;; 

    "Order Completed") 
    break
    ;; 

    *) print 'Not a main entree choice.';; 
esac 
done 

print 'Enjoy your meal.'
$ ./submenu.ksh 
1) broasted chicken 
2) prime rib 
3) stuffed lobster 
4) dessert 
5) Order Completed 
Main Menu: What would you like to order? 3 
Stuffed lobster with rice pilaf, rolls, and salad is $15.95. 
Main Menu: What would you like to order? 4 
1) apple pie 
2) sherbet 
3) fudge cake 
4) carrot cake 
Enter number for dessert choice: 3 
Triple layer fudge cake is $3.95. 
Main Menu: What would you like to order? 5
Enjoy your meal.
Related Post