bash - How can I re-display selection menu after a selection is chosen and performed
I'm guessing you really want something like this:
check_update () {
echo "Checking update"
}
reinstall_theme () {
echo "Reinstalling theme"
}
while true; do
options=("Check for update" "Reinstall theme")
echo "Choose an option:"
select opt in "${options[@]}"; do
case $REPLY in
1) check_update; break ;;
2) reinstall_theme; break ;;
*) echo "What's that?" >&2
esac
done
echo "Doing other things..."
echo "Are we done?"
select opt in "Yes" "No"; do
case $REPLY in
1) break 2 ;;
2) break ;;
*) echo "Look, it's a simple question..." >&2
esac
done
done
I've separated out the tasks into separate function to keep the first case
statement smaller. I've also used $REPLY
rather than the option string in the case
statements since this is shorter and won't break if you decide to change them but forget to update them in both places. I'm also choosing to not touch PS3
as that may affect later select
calls in the script. If I wanted a different prompt, I would set it once in and leave it (maybe PS3="Your choice: "
). This would give a script with multiple questions a more uniform feel.
I've added an outer loop that iterates over everything until the user is done. You need this loop to re-display the question in the first select
statement.
I've added break
to the case
statements, otherwise there's no way to exit other than interrupting the script.
The purpose of a select
is to get an answer to one question from the user, not really to be the main event-loop of a script (by itself). In general, a select
-case
should really only set a variable or call a function and then carry on.
A shorter version that incorporates a "Quit" option in the first select
:
check_update () {
echo "Checking update"
}
reinstall_theme () {
echo "Reinstalling theme"
}
while true; do
options=("Check for update" "Reinstall theme" "Quit")
echo "Choose an option: "
select opt in "${options[@]}"; do
case $REPLY in
1) check_update; break ;;
2) reinstall_theme; break ;;
3) break 2 ;;
*) echo "What's that?" >&2
esac
done
done
echo "Bye bye!"
Your do loop is endless and your select statement is outside of it. The script executes the select statement once and then stays in the do loop checking for case $opt over and over. My recommendation would be to put break after your case statement like this:
esac
break
done
Then, if you really want the whole script to repeat itself over and over again, create another loop that encloses everything from the select statement to the done statement.
I use this trick:
options=("First option" "Second option" "Quit")
PS3="So what? "
select opt in "${options[@]}"
do
case $opt in
"First option")
echo "First option"
;;
"Second option")
echo "Second option"
;;
"Quit")
echo "We are done..."
break
;;
*)
PS3="" # this hides the prompt
echo asdf | select foo in "${options[@]}"; do break; done # dummy select
PS3="So what? " # this displays the common prompt
;;
esac
done