I have a shell script that I want to ask the user if they want to continue. If they type 'n' and press enter the script will exit.
If they press 'y' and enter it will continue to run. I have this at the top of my script but it continues regardless of what I type.
What am I doing wrong ?
goon=
while [ -z $goon ]
do
echo -n 'Do you want to continue? '
read goon
if [[ $goon = 'n' ]]
then
break
fi
goon=
done
Use an infinity loop and case/esac like this:
while true
do
read -r -p 'Do you want to continue? ' choice
case "$choice" in
n|N) break;;
y|Y) echo 'Do your stuff here';;
*) echo 'Response not valid';;
esac
done
The 'break' statement will exit you out of your while loop.
If you want to exit the script you want to use 'exit'.
That works perfectly well for me if I get rid of the doubled square brackets:
if [ $goon = 'n' ]
Rather than echo + read, just use read -p
read -p "Do you want to continue? " goon
Here's a working example (== instead of = for equality testing)
goon=
while [ -z $goon ]
do
echo -n 'Do you want to continue? '
read goon
if [[ $goon == 'n' ]]
then
break
fi
goon=
done
Strange thing, the original works ok for me too ...
I'm less than positive, but it looks as though your if statement will always evaluate to false.
Here's a resource on BASH coding that explains how to use conditionals in the way you are attempting to.
http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-6.html#ss6.4
I think you mean "exit" instead of "break", if you want the whole script to exit.
Also, you aren't actually checking for "y", so it loops forever even if they do say "y".
if [[ $goon = 'n' ]]
then
exit
fi
if [[ $goon = 'y' ]]
then
break
fi
Try below script
#!/bin/bash
pause ()
{
REPLY=X
while [ "$REPLY" == "X" ] || [ "$REPLY" != "n" ]
do
echo -e "\t\tPress 'n' to continue\t\t\tPress 'x' to quit"
read -n1 -s
case "$REPLY" in
"x") exit ;;
"X") echo "case sensitive!!" ;;
"n") clear ;;
"N") echo "case sensitive!!" ;;
* ) echo "Invalid Option" ;;
esac
done
}
pause
echo "Hi"
am sure this script will give you only two options to move around...
Related
Using bash to write this script. For some reason my second IF condition is not working. I never get the message "FALSE result" when the condition is false. BTW, I need to nest two more if conditions but wanted to get this first one working. Any suggestions?
if [[ condition == "true" ]] ; then
echo "TRUE result"
if [[ condition == "false" ]] ; then
echo "FALSE result"
fi
fi
There are two problems here. The first is that condition is a fixed string, and will never be equal to either "true" or "false". If it's supposed to be a variable, you need to use "$condition" to get its value (the $ is required to get the variable's value, the double-quotes are sometimes needed to avoid weird parsing of the value). So something like if [[ "$condition" == "true" ]] ; then.
The second problem is that since the second if is nested inside the first, it'll never be tested if the first condition is false. That is, if $condition is "false", it'd test whether it's equal to "true", and since it isn't it'll skip everything up to the last fi, and hence never compare it to "false".
What you probably want is an elif (short for "else if") clause instead of a nested if -- that way it'll make the second test only if the first fails, instead of only if it succeeds. Note that an elif clause is not nested, but an extension of the original if statement, so it doesn't take an additional fi to close it. So something like this:
if [[ "$condition" == "true" ]] ; then
echo "TRUE result"
elif [[ "$condition" == "false" ]] ; then
echo "FALSE result"
fi
If you're comparing a something against a list of possible strings/patterns, it might be better to use a case statement:
case "$condition" in
true)
echo "TRUE result" ;;
false)
echo "FALSE result" ;;
maybe)
echo "MAYBE result" ;;
*)
echo "Unrecognized result" ;;
esac
read -p "Enter hostname(s): " HOSTS
for host in $HOSTS
do
echo "Test ssh-port on $host"
nc -zv -w 2 $host 22
if [ $? -ne 0 ]; then
echo "$host is not reachable.. See message above. Check hostname/ssh-deamon/firewall"
continue
fi
if [ "$host" = "host1" -o "$host" = "host2" ] ; then
message=$(ssh -q -t adminuser#$host "/usr/bin/sudo systemctl is-active sc4s.service")
echo "The SC4S service on $host is $message"
[ "$message" = "inactive" ] && echo "Please run the startsplunk script to restart the service on $host"
fi
done
I set a prompt to get user input Yy/Nn. Then I check if the response matches Y/y or N/n. However everytime it evaluates to true on "$prompt_1"="Y"/"y" even when you answer N/n. Now I am sure there is a reason why, however searching around brought me to a few solutions IG: Qoutes around the variables. But nothing has helped to resolve this.
#!/bin/bash
clear;
echo "Would you like to proceed with installation?"
read prompt_1;
echo $prompt_1;
if [ "$prompt_1"="Y" ] || [ "$prompt_1"="y" ]; then
echo "You've accepted installation";
elif [ "$prompt_1”="N"] || [ “$prompt_1"="n" ]; then
exit;
fi
You need to add spaces around the = operator:
if [ "$prompt_1" = "Y" ] || [ "$prompt_1" = "y" ]; then
echo "You've accepted installation";
elif [ "$prompt_1" = "N" ] || [ "$prompt_1" = "n" ]; then
exit;
fi
Or using the pattern-matching operator =~ in a [[...]] expression:
if [[ "$prompt_1" =~ ^[Yy]$ ]]; then
echo "You've accepted installation";
elif [[ "$prompt_1" =~ ^[Nn]$ ]]; then
exit
fi
The case statement solution.
case $prompt_1 in
[Yy]) echo "You've entered $prompt_1 and accepted installation."
##: do something here
;;
[Nn]) echo "You entered $prompt_1 and did not accepted the installation."
exit
;;
*|'') echo "Unknown option ${prompt_1:-empty}." ##: not [Nn] or [Yy] or empty.
exit
;;
esac
That is not restricted to bash anymore, it should work on other POSIX sh shells too.
Another suggestion, using case and lower case substitution:
case ${prompt_1,,} in
y|yes|"just do it")
echo "You've accepted installation"
# perform installation
;;
n|no|forget) exit;;
*) echo "Wrong answer, try again";;
esac
PS: Works in bash4 or later.
This question already has answers here:
How do I prompt for Yes/No/Cancel input in a Linux shell script?
(37 answers)
Closed 28 days ago.
How do I ask a yes/no type question in Bash?
I ask the question... echo "Do you like pie?"
And receive the answer... read pie
How do I do something if the answer is yes, or starts with y (so yes and yeah, etc, will work too).
I like to use the following function:
function yes_or_no {
while true; do
read -p "$* [y/n]: " yn
case $yn in
[Yy]*) return 0 ;;
[Nn]*) echo "Aborted" ; return 1 ;;
esac
done
}
So in your script you can use like this:
yes_or_no "$message" && do_something
In case the user presses any key other than [yYnN] it will repeat the message.
This works too:
read -e -p "Do you like pie? " choice
[[ "$choice" == [Yy]* ]] && echo "doing something" || echo "that was a no"
Pattern starting with Y or y will be taken as yes.
I like Jahid's oneliner. Here is a slight simplification of it:
[[ "$(read -e -p 'Continue? [y/N]> '; echo $REPLY)" == [Yy]* ]]
Here are some tests:
$ [[ "$(read -e -p 'Continue? [y/N]> '; echo $REPLY)" == [Yy]* ]] && echo Continuing || echo Stopping
Continue? [y/N]> yes
Continuing
$ for test_string in y Y yes YES no ''; do echo "Test String: '$test_string'"; echo $test_string | [[ "$(read -e -p 'Continue? [y/N]>'; echo $REPLY)" == [Yy]* ]] && echo Continuing || echo Stopping; done
Test String: 'y'
Continuing
Test String: 'Y'
Continuing
Test String: 'yes'
Continuing
Test String: 'YES'
Continuing
Test String: 'no'
Stopping
Test String: ''
Stopping
Update
In response to a comment, I'm going to add an adaptation to make this work in zsh.
Disclaimer
I would never write a shell script in zsh even though it is now my primary interactive shell. I still write all scripts in bash or sh. However, since you sometimes need to script modifications to your interactive shell (ex: source ~/dev/set_env), you might want to include prompting.
#! /usr/bin/env zsh
[[ "$(echo -n 'Continue? [y/N]> ' >&2; read; echo $REPLY)" == [Yy]* ]] \
&& echo Continuing \
|| echo Stopping
This works:
echo "Do you like pie?"
read pie
if [[ $pie == y* ]]; then
echo "You do! Awesome."
else
echo "I don't like it much, either."
fi
[[ $pie == y* ]] tests to see of the variable $pie starts with y.
Feel free to make this better if you'd like.
In contrast to the other answers this function gives you the possibility to set a default:
function askYesNo {
QUESTION=$1
DEFAULT=$2
if [ "$DEFAULT" = true ]; then
OPTIONS="[Y/n]"
DEFAULT="y"
else
OPTIONS="[y/N]"
DEFAULT="n"
fi
read -p "$QUESTION $OPTIONS " -n 1 -s -r INPUT
INPUT=${INPUT:-${DEFAULT}}
echo ${INPUT}
if [[ "$INPUT" =~ ^[yY]$ ]]; then
ANSWER=true
else
ANSWER=false
fi
}
askYesNo "Do it?" true
DOIT=$ANSWER
if [ "$DOIT" = true ]; then
< do some stuff >
fi
On the command line you would see
Do it? [Y/n] y
Here is a short function:
prompt(){ read -p "$1" a; return $(test $a = "y"); }
Usage (if the answer is y then do_something executed):
prompt "Do you want it?" && do_something
Usage with multiple commands:
prompt "Do you want it?" && {
do_something1
do_something2
}
I'm a noob to shell scripting and am wondering about this:
#!/usr/local/bin/bash
number=5
echo "Enter 'yes' to continue, 'no' to abort:"
read choice
if [ $choice = yes ]; then
while [ $number -lt 10 ]; do
echo "The script is now looping!"
done
elif [ $choice = no ]; then
echo "Loop aborted"
else
echo "Please say 'yes' or 'no'"
read choice
# What now?
fi
How would I go about the if statement rechecking your $choice (On line 13) if you do not specify "yes" or "no"?
Thank you.
You can put the code from "echo Enter..." till fi in an outer "while" loop. The while loop would loop until $choice is "yes" or "no". Remove the last "else" clause while doing this (it would be redundant).
P.S. you need to increment (or change) $number in your inner while loop. Otherwise, it will run infinitely.
You could keep track of whether to loop in a variable called invalid_choice
invalid_choice=true
while $invalid_choice; do
read choice
if [ "$choice" = "yes" ]; then
invalid_choice=false
...
elif [ "$choice" = "no" ]; then
invalid_choice=false
...
else
echo "Please say yes or no"
done
Or you could generalize it into a function if you need to do this a lot:
function confirm() {
local ACTION="$1"
read -p "$ACTION (y/n)? " -n 1 -r -t 10 REPLY
echo ""
case "$REPLY" in
y|Y ) return 0 ;;
* ) return 1 ;;
esac
}
confirm "Do something dangerous" || exit
This question already has answers here:
How do I prompt for Yes/No/Cancel input in a Linux shell script?
(37 answers)
Closed 9 years ago.
I want to put a quick "are you sure?" prompt for confirmation at the top of a potentially dangerous bash script, what's the easiest/best way to do this?
read -p "Are you sure? " -n 1 -r
echo # (optional) move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]
then
# do dangerous stuff
fi
I incorporated levislevis85's suggestion (thanks!) and added the -n option to read to accept one character without the need to press Enter. You can use one or both of these.
Also, the negated form might look like this:
read -p "Are you sure? " -n 1 -r
echo # (optional) move to a new line
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
[[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1 # handle exits from shell or function but don't exit interactive shell
fi
However, as pointed out by Erich, under some circumstances such as a syntax error caused by the script being run in the wrong shell, the negated form could allow the script to continue to the "dangerous stuff". The failure mode should favor the safest outcome so only the first, non-negated if should be used.
Explanation:
The read command outputs the prompt (-p "prompt") then accepts one character (-n 1) and accepts backslashes literally (-r) (otherwise read would see the backslash as an escape and wait for a second character). The default variable for read to store the result in is $REPLY if you don't supply a name like this: read -p "my prompt" -n 1 -r my_var
The if statement uses a regular expression to check if the character in $REPLY matches (=~) an upper or lower case "Y". The regular expression used here says "a string starting (^) and consisting solely of one of a list of characters in a bracket expression ([Yy]) and ending ($)". The anchors (^ and $) prevent matching longer strings. In this case they help reinforce the one-character limit set in the read command.
The negated form uses the logical "not" operator (!) to match (=~) any character that is not "Y" or "y". An alternative way to express this is less readable and doesn't as clearly express the intent in my opinion in this instance. However, this is what it would look like: if [[ $REPLY =~ ^[^Yy]$ ]]
use case/esac.
read -p "Continue (y/n)?" choice
case "$choice" in
y|Y ) echo "yes";;
n|N ) echo "no";;
* ) echo "invalid";;
esac
advantage:
neater
can use "OR" condition easier
can use character range, eg [yY][eE][sS] to accept word "yes", where any of its characters may be in lowercase or in uppercase.
Try the read shell builtin:
read -p "Continue (y/n)?" CONT
if [ "$CONT" = "y" ]; then
echo "yaaa";
else
echo "booo";
fi
This way you get 'y' 'yes' or 'Enter'
read -r -p "Are you sure? [Y/n]" response
response=${response,,} # tolower
if [[ $response =~ ^(y| ) ]] || [[ -z $response ]]; then
your-action-here
fi
If you are using zsh try this:
read "response?Are you sure ? [Y/n] "
response=${response:l} #tolower
if [[ $response =~ ^(y| ) ]] || [[ -z $response ]]; then
your-action-here
fi
Here's the function I use :
function ask_yes_or_no() {
read -p "$1 ([y]es or [N]o): "
case $(echo $REPLY | tr '[A-Z]' '[a-z]') in
y|yes) echo "yes" ;;
*) echo "no" ;;
esac
}
And an example using it:
if [[ "no" == $(ask_yes_or_no "Are you sure?") || \
"no" == $(ask_yes_or_no "Are you *really* sure?") ]]
then
echo "Skipped."
exit 0
fi
# Do something really dangerous...
The output is always "yes" or "no"
It's "no" by default
Everything except "y" or "yes" returns "no", so it's pretty safe for a dangerous bash script
And it's case insensitive, "Y", "Yes", or "YES" work as "yes".
I hope you like it,
Cheers!
This what I found elsewhere, is there a better possible version?
read -p "Are you sure you wish to continue?"
if [ "$REPLY" != "yes" ]; then
exit
fi
[[ -f ./${sname} ]] && read -p "File exists. Are you sure? " -n 1
[[ ! $REPLY =~ ^[Yy]$ ]] && exit 1
used this in a function to look for an existing file and prompt before overwriting.
echo are you sure?
read x
if [ "$x" = "yes" ]
then
# do the dangerous stuff
fi
#!/bin/bash
echo Please, enter your name
read NAME
echo "Hi $NAME!"
if [ "x$NAME" = "xyes" ] ; then
# do something
fi
I s a short script to read in bash and echo back results.
qnd: use
read VARNAME
echo $VARNAME
for a one line response without readline support. Then test $VARNAME however you want.