I'm new in Bash and I'm stuck with writing a prompt function which asks the user a given questions and accepts the answers yes, no and cancel. I know that there are already a lot of answers to similar questions here on SO but I wasn't able to find an answer that fulfills all my requirements.
Requirements:
The ask function must
- accept a question as parameter:
ask "are you happy?" - accept a answer in
[y/n/c]:y,Y,yes,yEs, etc. - return a value based on the answer:
truefor yes,falsefor no- the return value must be assignable to a variable to save it for later:
answer=$(ask "...?") - the return value must be directly useable by
ifstatements:if ask "...?" then;
- the return value must be assignable to a variable to save it for later:
- be able to halt the complete execution of the calling script for abort:
exit - ask again if the answer was not yes, no or cancel
- allow a default answer for empty input
- work in scripts that use
set -eas well asset +e
I came up with the following solution which doesn't work properly:
ask() { while true; do read -p "$1 [Y/n/a] " answer case $(echo "$answer" | tr "[A-Z]" "[a-z]") in y|yes|"" ) echo "true" ; return 0;; n|no ) echo "false"; return 1;; a|abort ) echo "abort"; exit 1;; esac done } # usage1 if ask "Are you happy?" >/dev/null; then # ... fi # usage2 answer=$(ask "Are you happy?") For example, the abort does only work when I use -e but then logically the no also causes the script to halt.
kill -0. Or just kill your parent... omg. Anyway,$(echo "$answer" | tr "[A-Z]" "[a-z]")it's simpler as${answer,,}set -ewould still halt when no is answered, right? What exactly does${answer,,}do?case $(echo "$answer" | tr "[A-Z]" "[a-z]") inyou can usecase "${answer,,}" in.how do I handle exit status?answer=$(seomthing) || ret=$?; if ((ret == 0)); then :; elif ((ret == 1)); then .....Can I handle the exit status in the ask function?Well, there is no function exit status inside the function, it's after the function returns.Because I don't want the handling to happen in the calling codeThem if you wantexit 1to terminate it all, you can kill your whole process group withkill -0or you can't run in a subshell.$(..)starts a subshell.