ask – yes/no question prompt in Bash
This is a general-purpose script to ask Yes/No questions in Bash, either with or without a default answer. It keeps repeating the question until it gets a valid answer.
Table of Contents
The script
Save this somewhere in PATH
with the name ask
, and make it executable (chmod +x ask
).
#!/usr/bin/env bash
set -euo pipefail
prompt=${1:-}
# Display usage info if no prompt is given
if [[ -z $prompt ]]; then
echo "Usage: $(basename "$0") <prompt> [default]" >&2
exit 2
fi
# Determine the default value
if [[ ${2:-} = 'Y' || ${2:-} = 'y' ]]; then
default='Y'
yn='Y/n'
elif [[ ${2:-} = 'N' || ${2:-} = 'n' ]]; then
default='N'
yn='y/N'
else
default=''
yn='y/n'
fi
# Ask the question (not using "read -p" as it uses stderr not stdout)
echo -n "$prompt [$yn] "
# Repeat until we get a valid answer
result=
while [[ -z $result ]]; do
# Read a single character, without echoing it
read -rsn1 reply
# If the user pressed enter, use the default value
if [[ -z $reply ]]; then
reply=$default
fi
# Check if the reply is valid
case "$reply" in
Y*|y*) result=0 ;;
N*|n*) result=1 ;;
esac
done
# Output the reply, or the default value, so the user can see it
echo "$reply"
# Exit with the relevant code for true or false
exit $result
Example usage
if ask "Do you want to do such-and-such?"; then
echo "Yes"
else
echo "No"
fi
Default to Yes if the user presses enter without giving an answer:
if ask "Do you want to do such-and-such?" Y; then
echo "Yes"
else
echo "No"
fi
Default to No if the user presses enter without giving an answer:
if ask "Do you want to do such-and-such?" N; then
echo "Yes"
else
echo "No"
fi
Only do something if you say Yes:
if ask "Do you want to do such-and-such?"; then
said_yes
fi
Only do something if you say No:
if ! ask "Do you want to do such-and-such?"; then
said_no
fi
Or if you prefer the shorter versions:
ask "Do you want to do such-and-such?" && said_yes
ask "Do you want to do such-and-such?" || said_no
Other notes
If input/output to your script may be redirected from somewhere else, but you still want to prompt the user interactively, you may need to redirect it again for this one call:
if ask "Something" </dev/tty >/dev/tty; then
said_yes
fi
In a previous version of this article, I defined a function (ask() { ... }
) rather than a script, because that's what I was used to doing in PHP - but I've since realised this is the more standard approach (the Unix philosophy). The usage is the same either way, but a function needs to use return
rather than exit
.