if statement checking regex expression not working - shell

I have start learning shell programming today, what I am trying out is to do a simple option menu with 3 choices and if the user key in 1,2 or 3, it will be a valid input. anything besides 1,2,3 will be a invalid input.I have tried it out but it's not working as in nothing happened with my codes below.
Please advice thanks.
#!/bin/bash
while :
do
clear
#display menu
echo "1) choice 1"
echo "2) choice 2"
echo "3) choice 3"
read -p "Enter choice: " choice
regex = "[1-3]"
if [[ $choice -ne $regex ]]; then
echo "Invalid input"
else
case $choice in
1) echo "this is choice one"
2) echo "this is choice two"
3) echo "this is choice three"
esac
fi
done

You're not comparing it as a regex. Say:
if [[ ! $choice =~ $regex ]]; then
Moreover, you shouldn't put spaces are = during assignment. Say:
regex="[1-3]"
From the manual:
An additional binary operator, ‘=~’, is available, with the same
precedence as ‘==’ and ‘!=’. When it is used, the string to the right
of the operator is considered an extended regular expression and
matched accordingly

Don't clear or you won't see anything.
Errors
Remove the blanks around =:
regex="[1-3]"
Your cases must end with ;;:
1) echo "this is choice one";;
2) echo "this is choice two";;
3) echo "this is choice three";;
Suggestions
Introduce an exit case:
'x') exit 0;;
The test [[ ]] is not needed if you use a default case as the last case:
*) echo "invalid input";;

Related

Return to previous commands in bash script?

I'm trying to implement a prev option in my bash script to go back to the previous "menu", as well as a way for the script to ask for user input again if no variable is set for $name.
Heres my bash script:
#!/bin/bash
#Menu() {
for (( ; ; ))
do
beginORload=
echo "Choose option:"
echo "1 - Begin"
echo "2 - Load"
read -p "?" beginORload
#}
#Begin() {
if [ "$beginORload" -eq "1" ]
then
clear
for (( ; ; ))
do
echo "Beginning. What is your name?"
read -p "?" name
#If "prev" specified, go back to #Menu()
if [ "$name" -eq "prev" ]
then
Menu
fi
#If nothing specified, return to name input
if [ -z ${name+x} ]
then
Begin
else
break
fi
echo "Hi $name !"
done
fi
done
In batch, I could simply do:
:menu
echo Choose option:
echo 1 - Begin
echo 2 - Load
[...]
:begin
[...]
if "%name%==prev" goto menu
if "%name%==" goto begin
the issue is I keep running into errors all over the place, and I can't figure out what to type to get it to work
im running Yosemite btw. Thankyou
Something like this is close to what you expect:
while [[ $answer -ne '3' ]];do
echo "Choose option:"
echo "1 - Begin"
echo "2 - Load"
echo "3 - Exit"
read -p "Enter Answer [1-2-3]:" answer
case "$answer" in
1) while [[ "$nm" == '' ]];do read -p "What is your Name:" nm;done # Keep asking for a name if the name is empty == ''
if [[ $nm == "prev" ]];then nm=""; else echo "Hello $nm" && break; fi # break command breaks the while wrapper loop
;;
2) echo 'Load' ;;
3) echo 'exiting...' ;; # Number 3 causes while to quit.
*) echo "invalid selection - try again";; # Selection out of 1-2-3 , menu reloaded
esac # case closing
done # while closing
echo "Bye Bye!"
As a general idea you can wrap up your case selection in a while loop which will break under certain circumstances (i.e If Option 3 is selected or if a valid name is given (not blank - not prev)
PS1: In bash you compare integers with -eq , -ne, etc but you compare strings with == or !=
PS2: Check the above code online here

If statement syntax eror

I am trying to figure out how to check to see if the first input will end with .txt. It seems like the standard if statement syntax does not apply to my code based upon the way I am getting the input. Does anyone know the proper syntax for the else if statement in my first if statement in my code?
#!/bin/sh
printf "%b %b\n" "$*"
if [ "$1" = "-help" ]
then
echo "Cool Beans"
elif [ "$1" = "*.txt" ]
then
echo "text recd"
else
echo "first input not valid"
fi
if [ "$2" = "-help" ]
then
echo "help options"
else
echo "second input not valid"
fi
In order for pattern matching to work, can use Bash double-bracketed conditionals (while removing the quotes, which disable the matching) :
elif [[ "$1" = *.txt ]]
You can also use regular expression matching :
elif [[ "$1" =~ [.]txt$ ]]
Note that you must escape the period (or put it in brackets like I did) to prevent its special meaning of "any character" to be disabled, as well as anchor the regex to the end with $ so that you are sure you are matching the extension, not a sub-string inside the file name.
If you want something that is not bash-specific, you can try :
elif [ "${1##*.}" = txt ]
The "${1##*.}" expansion removes the longest string that starts from the beginning of the variable named 1 (could be any variable) and ends with a period, leaving the extension only.
You can also use a case statement for POSIX-compatible pattern matching:
printf "%b %b\n" "$*"
case $1 in
-help) echo "Cool Beans" ;;
*.txt) echo "text recd" ;;
*) echo "first input not valid"
esac
case $2 in
-help) echo "help options" ;;
*) echo "second input not valid" ;;
esac

Integer comparison in Bash using if-else

I have a variable called choice. Now, I try to use if to compare the entered value:
read $choice
if [ "$choice" == 2 ];then
#do something
elif [ "$choice" == 1 ];then
#do something else
else
echo "Invalid choice!!"
fi
The output goes directly to invalid choice if I enter either 1 or 2. I tried to put quotes around 1 and 2 inside the if statement. Still didn't work. Using -eq gives me an error "Unary operator expected".What am I doing wrong here?
Your read line is incorrect. Change it to:
read choice
i.e. use the name of the variable you want to set, not its value.
-eq is the correct test to compare integers. See man test for the descriptions (or man bash).
An alternative would be using arithmetic evaluation instead (but you still need the correct read statement):
read choice
if (( $choice == 2 )) ; then
echo 2
elif (( $choice == 1 )) ; then
echo 1
else
echo "Invalid choice!!"
fi
For your example, case seems to be what you probably want:
read choice
case "$choice" in
"1")
echo choice 1;
;;
"2")
echo choice 2;
;;
*)
echo "invalid choice"
;;
esac
An unpractical answer, just to point out that since read takes a variable name, the name can be specified by another variable.
choice=choice # A variable whose value is the string "choice"
read $choice # $choice expands to "choice", so read sets the value of that variable
if [[ $choice -eq 1 ]]; then # or (( choice == 1 ))

Shell script that asks user to continue with a y/n

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...

How do I prompt a user for confirmation in bash script? [duplicate]

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.

Resources