Skip to content
Create a gist now

Instantly share code, notes, and snippets.

Bash: General-purpose Yes/No prompt function ("ask")
# This is a general-purpose function 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.
ask() {
# http://djm.me/ask
while true; do
if [ "${2:-}" = "Y" ]; then
prompt="Y/n"
default=Y
elif [ "${2:-}" = "N" ]; then
prompt="y/N"
default=N
else
prompt="y/n"
default=
fi
# Ask the question (not using "read -p" as it uses stderr not stdout)
echo -n "$1 [$prompt] "
# Read the answer (use /dev/tty in case stdin is redirected from somewhere else)
read REPLY </dev/tty
# Default?
if [ -z "$REPLY" ]; then
REPLY=$default
fi
# Check if the reply is valid
case "$REPLY" in
Y*|y*) return 0 ;;
N*|n*) return 1 ;;
esac
done
}
# 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 version:
ask "Do you want to do such-and-such?" && said_yes
ask "Do you want to do such-and-such?" || said_no
@tomm174
tomm174 commented Jan 10, 2013

Yes ! - thank you.
This is just right - there are a lot of egos out there showing how 'clever' they are by making it over-complicated.
This does just what is required for a fn that prompts and can except Y or N as default, and the usage examples are clear

@dkirrane

Hi,

This function is exactly what I needed.

But I'd also like to add a batch option for it.
So, if -B is set the ask function will not prompt and just use the default. Any advice how best do this?

@swiftarrow

Hi! Thanks alot for this function!

One thing you might like to fix: http://www.shellcheck.net/ reports that the keyword function is optional in bash and incompatible with other shells. Also, there should be brackets () after the function name.

Thanks!

@Willscrlt

I was working on something similar to this that included a timeout, and your snippet gave me some helpful inspiration. Thanks!

@davejamesmiller
Owner

@dkirrane: I normally do something like this:

if [ "$1" = "-B" ]; then
  batch=true
else
  batch=false
fi

if $batch || ask "Prompt"; then
  # Do something
fi

Or if you're only asking one question:

if [ "$1" = "-B" ] || ask "Prompt"; then
  # Do something
fi
@davejamesmiller
Owner

@swiftarrow - Updated, thanks

@caelor
caelor commented Dec 10, 2014

I've forked and made a minor amendment that you might want to include as a revision - it forces the use of /dev/tty (the controlling terminal) as the input to the read. That way, the function can be called within loops that use stdin for something else (like reading files).

@davejamesmiller
Owner

@carlor - Done, thanks for sharing

@dtigue
dtigue commented Apr 12, 2015

Perfect! I can't tell you how many of my scripts will include your function from now on. Thanks!

@muvvas
muvvas commented May 6, 2016 edited

Hi Dave
Thanks for the script
in my script i m using debug and error redirect using exec 2 >/tmp/somefile
ex
#/bin/bash
set -x
exec 2>/tmp/somefile
here askfunction{}
if ask "do you want to install ?"; then
do something
fi

when i run the script,its not asking the Question on console,its going to log file
will you pleas help me how can i use set -x and exec 2 ,,to get the only debuging output to file and ask question on console

Thanks,
Srikanth

@davejamesmiller
Owner
davejamesmiller commented May 6, 2016 edited

@muvvas:

Two possibilities:

  1. Output the prompt yourself:

    echo -n "$1 [$prompt] "
    read REPLY </dev/tty
  2. Redirect the prompt from stderr to stdout:

    read -p "$1 [$prompt] " REPLY 2>&1 </dev/tty

Personally I prefer the first one even though it's one more line. I have updated the Gist to use that because it seems more logical to me to use stdout (I never realised it uses stderr).

http://stackoverflow.com/questions/5983988/bash-read-and-stderr-redirection

@muvvas
muvvas commented May 9, 2016

thanks did the option 1.thanks for your update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.