Well I thought this dynamic menu was going to be a simple example of looping through the input file that holds the menu structure, parsing the menu options line, then using the ksh select construct to prompt, but my select construct is not prompting and instead seems to be taking the input from the while loop read. Can anyone spot why this is happening? ksh93 on Solaris by the way. I thought maybe it was IFS but even if I reset it inside the main loop the same happens.
#!/usr/dt/bin/dtksh
typeset -r -x DYNMENUFILE=${0}.dat # Menu file
typeset -r MAINPROMPT="Enter your selection: "
typeset -x PS3=$MAINPROMPT # PS3 is the prompt for the select construct.
typeset -r RESPONSEFILE="${0}_${USER}.out"
> $RESPONSEFILE # Create or clear the response file.
# Read lines from the menu file.
while IFS="|" read heading option1_in option2_in option3_in option4_in the_rest
do
# Loop until a correct answer is received.
while :
do
# clear
print "\n$heading\n"
select option in $option1_in $option2_in $option3_in $option4_in
do
case $REPLY in # REPLY is set by the select construct,
# and is the number of the selection.
1) ;& # Fall through
2) ;& # Fall through
3) ;& # Fall through
4) print "${heading}: $option" >> $RESPONSEFILE
break # Break out 2 levels (get the next menu line)
;;
*) # Always code for the unexpected.
print "\nUnknown option [${REPLY}]"
sleep 2
break # redisplay the current menu
;;
esac
done # End select
done # End while true
done < $DYNMENUFILE
exit 0
I get the menu for line 1 as expected, but immediately get the unknown option error with the reply being the entire line 2 from the file, etc.
Output:
You redirect stdin to read the file. 'select' reads an option from stdin. So 'select' ends up reading from the file.. Open it into another fd, and read from that.
I'm not sure if it's -u5 or -u 5.
exec 5<$DYNMENUFILE
while IFS="|" read -u5 option1_in option2_in option3_in option4_in the_rest
do
...
done
exec 5<&-
DOH! Here's the corrected example then which works. Thanks Corona688!
#!/usr/dt/bin/dtksh
typeset -r -x DYNMENUFILE=${0}.dat # Menu file
typeset -r MAINPROMPT="Enter your selection: "
typeset -x PS3=$MAINPROMPT # PS3 is the prompt for the select construct.
typeset -r RESPONSEFILE="${0}_${USER}.out"
> $RESPONSEFILE # Create or clear the response file.
# Create file desriptor 5 as input from the menu file, as the select construct needs to
# read from stdin too.
exec 5<$DYNMENUFILE
# Read lines from the file descriptor associated with the menu file.
while IFS="|" read -u5 heading option1_in option2_in option3_in option4_in the_rest
do
# Loop until a valid option is entered.
while :
do
clear
print "\n$heading\n"
select option in $option1_in $option2_in $option3_in $option4_in
do
case $REPLY in # REPLY is set by the select construct,
# and is the number of the selection.
1) ;& # Fall through
2) ;& # Fall through
3) ;& # Fall through
4) print "${heading}: $option" >> $RESPONSEFILE
print "\nYou selected: ${heading}: $option"
sleep 2
break 2 # Break out 2 levels (get the next menu line)
;;
*) # Always code for the unexpected.
print "\nUnknown option [${REPLY}]"
sleep 2
break # redisplay the current menu
;;
esac
done # End select
done # End while true
done # End reading menu items
# Close fd 5.
exec 5<&-
exit 0
Sure, that's just my preference, I usually set it up like this for future changes where someone behind me (a less experienced developer perhaps) may need to add selection-specific code. If so, the framework if you will is ready for it.
I recall that is a habit I picked up when I coded switch statements in C years ago. Maybe it was a standard where I worked or something.
That's impressive! It works perfect
I have one more doubt? What if i want to store the option entered and not the string corresponding to the option in the out file?