I want to pause input in a shell script, and prompt the user for choices.
The standard Yes
, No
, or Cancel
type question.
How d
In response to others:
You don't need to specify case in BASH4 just use the ',,' to make a var lowercase. Also I strongly dislike putting code inside of the read block, get the result and deal with it outside of the read block IMO. Also include a 'q' for quit IMO. Lastly why type 'yes' just use -n1 and have the press y.
Example: user can press y/n and also q to just quit.
ans=''
while true; do
read -p "So is MikeQ the greatest or what (y/n/q) ?" -n1 ans
case ${ans,,} in
y|n|q) break;;
*) echo "Answer y for yes / n for no or q for quit.";;
esac
done
echo -e "\nAnswer = $ans"
if [[ "${ans,,}" == "q" ]] ; then
echo "OK Quitting, we will assume that he is"
exit 0
fi
if [[ "${ans,,}" == "y" ]] ; then
echo "MikeQ is the greatest!!"
else
echo "No? MikeQ is not the greatest?"
fi
Use the read
command:
echo Would you like to install? "(Y or N)"
read x
# now check if $x is "y"
if [ "$x" = "y" ]; then
# do something here!
fi
and then all of the other stuff you need
This solution reads a single character and calls a function on a yes response.
read -p "Are you sure? (y/n) " -n 1
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
do_something
fi
read -e -p "Enter your choice: " choice
The -e
option enables the user to edit the input using arrow keys.
If you want to use a suggestion as input:
read -e -i "yes" -p "Enter your choice: " choice
-i
option prints a suggestive input.
I've used the case
statement a couple of times in such a scenario, using the case statment is a good way to go about it. A while
loop, that ecapsulates the case
block, that utilizes a boolean condition can be implemented in order to hold even more control of the program, and fulfill many other requirements. After the all the conditions have been met, a break
can be used which will pass control back to the main part of the program. Also, to meet other conditions, of course conditional statements can be added to accompany the control structures: case
statement and possible while
loop.
Example of using a case
statement to fulfill your request
#! /bin/sh
# For potential users of BSD, or other systems who do not
# have a bash binary located in /bin the script will be directed to
# a bourne-shell, e.g. /bin/sh
# NOTE: It would seem best for handling user entry errors or
# exceptions, to put the decision required by the input
# of the prompt in a case statement (case control structure),
echo Would you like us to perform the option: "(Y|N)"
read inPut
case $inPut in
# echoing a command encapsulated by
# backticks (``) executes the command
"Y") echo `Do something crazy`
;;
# depending on the scenario, execute the other option
# or leave as default
"N") echo `execute another option`
;;
esac
exit
Here's a longer, but reusable and modular approach:
0
=yes and 1
=nozsh
and bash
.Note that the N
is capitalsed. Here enter is pressed, accepting the default:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]?
Also note, that [y/N]?
was automatically appended.
The default "no" is accepted, so nothing is echoed.
Re-prompt until a valid response is given:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]? X
Show dangerous command [y/N]? y
rm *
Note that the Y
is capitalised:
$ confirm_yes "Show dangerous command" && echo "rm *"
Show dangerous command [Y/n]?
rm *
Above, I just pressed enter, so the command ran.
y
or n
$ get_yes_keypress "Here you cannot press enter. Do you like this [y/n]? "
Here you cannot press enter. Do you like this [y/n]? k
Here you cannot press enter. Do you like this [y/n]?
Here you cannot press enter. Do you like this [y/n]? n
$ echo $?
1
Here, 1
or false was returned. Note that with this lower-level function you'll need to provide your own [y/n]?
prompt.
# Read a single char from /dev/tty, prompting with "$*"
# Note: pressing enter will return a null string. Perhaps a version terminated with X and then remove it in caller?
# See https://unix.stackexchange.com/a/367880/143394 for dealing with multi-byte, etc.
function get_keypress {
local REPLY IFS=
>/dev/tty printf '%s' "$*"
[[ $ZSH_VERSION ]] && read -rk1 # Use -u0 to read from STDIN
# See https://unix.stackexchange.com/q/383197/143394 regarding '\n' -> ''
[[ $BASH_VERSION ]] && </dev/tty read -rn1
printf '%s' "$REPLY"
}
# Get a y/n from the user, return yes=0, no=1 enter=$2
# Prompt using $1.
# If set, return $2 on pressing enter, useful for cancel or defualting
function get_yes_keypress {
local prompt="${1:-Are you sure [y/n]? }"
local enter_return=$2
local REPLY
# [[ ! $prompt ]] && prompt="[y/n]? "
while REPLY=$(get_keypress "$prompt"); do
[[ $REPLY ]] && printf '\n' # $REPLY blank if user presses enter
case "$REPLY" in
Y|y) return 0;;
N|n) return 1;;
'') [[ $enter_return ]] && return "$enter_return"
esac
done
}
# Credit: http://unix.stackexchange.com/a/14444/143394
# Prompt to confirm, defaulting to NO on <enter>
# Usage: confirm "Dangerous. Are you sure?" && rm *
function confirm {
local prompt="${*:-Are you sure} [y/N]? "
get_yes_keypress "$prompt" 1
}
# Prompt to confirm, defaulting to YES on <enter>
function confirm_yes {
local prompt="${*:-Are you sure} [Y/n]? "
get_yes_keypress "$prompt" 0
}