I've written a Bash function that can ask a simple yes/no question.
- The "yes/no" prompt is translated to the user's language (the question must be localised by the caller).
- Input is accepted in the same language.
- Language falls back to English if message catalogue is not available.
- The question is repeated until a valid response is entered.
- One reply may be specified as default if the user just gives an empty string, which is presented in capital letters, as is the convention - or if the language doesn't have uppercase/lowercase distinction, then it's highlighted with
[⋯]
. - If no default is specified, empty input is not valid.
- It returns success or failure so it can be used directly as a command in conditionals.
- Shellcheck reports no issues.
#!/bin/bash
# ask_with_default message [0|1]
# First argument is the question to ask
# Second argument, if present, is 0 or 1 to default to yes or no, respectively
ask_with_default() {
local messages true false answer default
readarray -t messages < <(locale LC_MESSAGES)
true=${messages[2]:=yes}
false=${messages[3]:=no}
default=${2-}
case "$default" in
[01])
local tf=(true false)
local -n d=${tf[$default]}
if [ "${d,,}" != "${d^^}" ]
then
# upcase the default
true=${true,,}
false=${false,,}
d=${d^^}
else
# alt. highlight if upper case is same as lower
d="[$d]" # or "$d(*)" etc
fi
;;
'')
# no default
;;
*)
# Invalid, so ignore, with a warning
echo >&2 "Usage: ask_with_default message [0|1]"
default=
;;
esac
while true
read -rp "$1 ($true/$false) " answer
do if [[ "$answer" =~ ${messages[0]:=^[yY]} ]]
then
return 0
elif [[ "$answer" =~ ${messages[1]:=^[nN]} ]]
then
return 1
elif ! [ "$answer" ] && [ "$default" ]
then
return "$default"
fi
done
}
Example usage (I haven't bothered to translate the question here, just for clarity)
if ask_with_default "Is this good?" 0 then echo "That makes me happy." else echo "I'm sorry you don't like it." fi
Here's the yes/no selection in a handful of locales I have available here ():
- C:
(YES/no)
- cy:
(IE/na)
- gd:
(THA/chan eil)
- kl:
(AAP/naagga)
- el:
(ΝΑΙ/όχι)
- ru_UA:
(ДА/нет)
- ko:
([예]/아니요)
- ja:
([はい]/いいえ)
Concerns
- General review of the code - anything that could be clearer, more efficient or in any other way better?
- Is the use of
[⋯]
to highlight the default in non-cased scripts clear and understandable for users? Or is there an existing convention I could use instead?