Initial thoughts were towards maintaining some sort of call stack for the menu/functions, with return codes (or more likely variable settings) determining how the 'parent' menu/function is to function upon return from the child menu/function call. And I'd probably look at something along this lines if there's a need to maintain some sort of recursive data sets (eg, appending to data when going 'down', stripping off data when going 'up') but there's nothing in OP's question indicating this level of data manipulation so ...
A simplistic approach would be to have each menu choice/action designate the 'next' command (eg, break
, <function_name>
) to be called, with a simple while true
loop at the top level executing the 'next' command.
Implementing OP's sample menus with some verbose bash
code, with undefined actions/menus implemented as simple echo
calls:
##########
menu_main() {
printf "\n#### current function: ${FUNCNAME}\n"
local menu choice
menu="
1 - Option 1
2 - Option 2
3 - Quit (exit command)
"
unset next
while true
do
echo "${menu}"
read -p "Pick Number> " choice
case $choice in
1) next=menu_1 ;;
2) echo "choice #${choice}, do something" ;;
3) next=break ;;
*) echo "Invalid choice, please try again";;
esac
[[ -n "${next}" ]] && break
done
}
##########
menu_1() {
printf "\n#### current function: ${FUNCNAME}\n"
local menu choice
menu="
1 - Sub-Option 1
2 - Sub-Option 2
3 - back to main menu
"
unset next
while true
do
echo "${menu}"
read -p "Pick Number> " choice
case $choice in
1) next=menu_1_1 ;;
2) echo "choice #${choice}, do something" ;;
3) next=menu_main ;;
*) echo "Invalid choice, please try again";;
esac
[[ -n "${next}" ]] && break
done
}
##########
menu_1_1() {
printf "\n#### current function: ${FUNCNAME}\n"
local menu choice
menu="
1 - Sub-Sub-Option 1
2 - Sub-Sub-Option 2
3 - back Sub-option menu
4 - back to main menu
"
unset next
while true
do
echo "${menu}"
read -p "Pick Number> " choice
case $choice in
1) echo "choice #${choice}, do something" ;;
2) echo "choice #${choice}, do something" ;;
3) next=menu_1 ;;
4) next=menu_main ;;
*) echo "Invalid choice, please try again";;
esac
[[ -n "${next}" ]] && break
done
}
NOTES:
- this code merely demonstrates the overall concept
- several variations could be made including the use of
select
, the use of a single 'generic' menu function that uses input args to access a specific menu's items/actions (stored in arrays), etc
- unlike OP's sample code that shows a nested function call, this approach makes NO nested function calls; OP is responsible for insuring each function, upon returning, instructs the parent
while true
loop as to the 'next' operation
Taking for a test drive:
next=menu_main
while true
do
echo "#### next: ${next}"
${next}
done
The output from exercising all menu options:
#### next: menu_main
#### current function: menu_main
1 - Option 1
2 - Option 2
3 - Quit (exit command)
Pick Number> 1
#### next: menu_1
#### current function: menu_1
1 - Sub-Option 1
2 - Sub-Option 2
3 - back to main menu
Pick Number> 1
#### next: menu_1_1
#### current function: menu_1_1
1 - Sub-Sub-Option 1
2 - Sub-Sub-Option 2
3 - back Sub-option menu
4 - back to main menu
Pick Number> 1
choice #1, do something
1 - Sub-Sub-Option 1
2 - Sub-Sub-Option 2
3 - back Sub-option menu
4 - back to main menu
Pick Number> 2
choice #2, do something
1 - Sub-Sub-Option 1
2 - Sub-Sub-Option 2
3 - back Sub-option menu
4 - back to main menu
Pick Number> 3
#### next: menu_1
#### current function: menu_1
1 - Sub-Option 1
2 - Sub-Option 2
3 - back to main menu
Pick Number> 1
#### next: menu_1_1
#### current function: menu_1_1
1 - Sub-Sub-Option 1
2 - Sub-Sub-Option 2
3 - back Sub-option menu
4 - back to main menu
Pick Number> 4
#### next: menu_main
#### current function: menu_main
1 - Option 1
2 - Option 2
3 - Quit (exit command)
Pick Number> 1
#### next: menu_1
#### current function: menu_1
1 - Sub-Option 1
2 - Sub-Option 2
3 - back to main menu
Pick Number> 2
choice #2, do something
1 - Sub-Option 1
2 - Sub-Option 2
3 - back to main menu
Pick Number> 3
#### next: menu_main
#### current function: menu_main
1 - Option 1
2 - Option 2
3 - Quit (exit command)
Pick Number> 2
choice #2, do something
1 - Option 1
2 - Option 2
3 - Quit (exit command)
Pick Number> 3
#### next: break
$ # return back to the console's command prompt
select
statement? This seems like reinventing a wheel.