Integer comparison in Bash using if-else - bash

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

Related

Access variables using an external string.[SHELL script]

I currently have code as
if [[ "$FIRSTFLAG" == 1 ]] ; then
all_comp+=("FIRST")
fi
if [[ "$SECONDFLAG" == 1 ]] ; then
all_comp+=("SECOND")
fi
if [[ "$THIRDFLAG" == 1 ]] ; then
all_comp+=("THIRD")
fi
all_comp is just an array
So, im working on a solution to reduce the repetitive code
I know that we can use case here.
I wonder if there is a solution that can be done using array and for loop \
For example(I know its syntactically wrong)
names=("FIRST" "SECOND" "THIRD")
for i in $names[#]; do
if [[ ${i}FLAG == 1 ]]; then <- This line is the issue
all_comp+=("$i")
fi
done
So please tell me if there is a solution for such code example
You need to use indirect expansion by saving the constructed variable name, e.g. iflag=${i}FLAG, then you can use access the indirect expansion with ${!iflag}, e.g.
FIRSTFLAG=1
SECONDFLAG=0
THIRDFLAG=1
all_comp=()
names=("FIRST" "SECOND" "THIRD")
for i in ${names[#]}; do
iflag=${i}FLAG
if [[ ${!iflag} == 1 ]]; then
all_comp+=("$i")
fi
done
echo ${all_comp[#]} # Outputs: FIRST THIRD
Oh another answer, you can make use of the arithmetic expansion operator (( )) i.e.
FIRSTFLAG=1
SECONDFLAG=0
THIRDFLAG=1
all_comp=()
names=("FIRST" "SECOND" "THIRD")
for i in ${names[#]}; do
if (( ${i}FLAG == 1 )); then
all_comp+=("$i")
(( ${i}FLAG = 99 ))
fi
done
echo ${all_comp[#]} # FIRST THIRD
echo $FIRSTFLAG # 99
echo $SECONDFLAG # 0
echo $THIRDFLAG # 99
Reference:
https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html#Shell-Parameter-Expansion

if in case in while (bash number guessing game)

I am programming a little number-guessing game in bash.
This is the code so far:
#!/bin/bash
#Number guessing
read -p "Who are you? " name
echo "Welcome, ${name}!"
read -p "How high do you want to guess? " level
number=$(($RANDOM % $level))
((attempts++))
while [[ ${guess} != ${number} ]]
do
read -p "Whats the number? " guess
case $guess in
$number) echo "Correct! You needed ${attempts} attempts"
break
;;
*) echo "Wrong..."
((attempts++))
;;
esac
if [[ ${guess} > ${number} ]]
then
echo "Above."
else
echo "Below."
fi
done
This asks for the users name, how high the numbers that have to be guessed go and then generates a random number based on $level. What I want to do is a echo whether the entered number was above or below the guessed number. The if at the end of the while-loop doesnt work and the same if in the last case *) echo "Wrong" doesnt work either. Is it possible to have such an if in a case in a while loop or do you have another solution?
Have a nice day
!= and > are string comparison operators inside [[ ... ]]; you want integer comparison.
while [[ ${guess} -ne ${number} ]]
if [[ ${guess} -gt ${number} ]]
or better in bash, use an arithmetic statement where you can use the normal operators.
while (( guess != number ))
if (( guess > number ))

Why do I get bash integer expression error from [ ${guess[0]} -eq num ]?

I am trying to prompt the user to guess a value between 0-9. I am getting the error integer expression expected. I don't understand why can someone explain where I am going wrong?
num=8
echo "Enter a value between 0-9"
read -a guess
if [ ${guess[0]} -eq num ] ; then
echo "You guesses the right number"
elif [ ${guess[0]} -gt num ] ; then
echo "You guessed too high"
elif [ ${guess[0]} -lt num ] ; then
echo "You guess too low"
fi
To make only the minimum number of changes necessary for this code to run correctly:
#!/bin/sh
num=8
echo "Enter a value between 0-9"
read guess
if [ "$guess" -eq "$num" ] ; then
echo "You guesses the right number"
elif [ "$guess" -gt "$num" ] ; then
echo "You guessed too high"
elif [ "$guess" -lt "$num" ] ; then
echo "You guess too low"
fi
Notes:
Since you're reading only a single value, no compelling reason to use an array -- just as easy to take out the -a argument to read; doing this also makes your code compatible with POSIX sh, and thus with #!/bin/sh on all systems with POSIX-compliant shells.
You need to expand your variables when using test (or [). $num, not bare $num; the latter is only possible in a numeric context, whereas test is a regular command as much as the parser is concerned -- it doesn't create any special context at a syntax level.
Because [ is a regular command, you need spaces after it, just like any other command name.
Because [ is a regular command, you need spaces before the ] it expects as its last argument -- same as when passing arguments to anything else.
If your shell were bash (your script started with #!/bin/bash), you could use a math context: if (( guess == num )), or if (( guess > num )). This is a math context, and has special parsing rules.

if statement checking regex expression not working

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";;

if arguments is equal to this string, define a variable like this string

I am doing some bash script and now I got one variable call source and one array called samples, like this:
source='country'
samples=(US Canada Mexico...)
as I want to expand the number of sources (and each source has its own samples) I tried to add some arguments to do this. I tried this:
source=""
samples=("")
if [ $1="country" ]; then
source="country"
samples="US Canada Mexico..."
else
echo "try again"
fi
but when I ran my script source countries.sh country it didn't work.
What am I doing wrong?
Don't forget about spaces:
source=""
samples=("")
if [ $1 = "country" ]; then
source="country"
samples="US Canada Mexico..."
else
echo "try again"
fi
You can use either "=" or "==" operators for string comparison in bash. The important factor is the spacing within the brackets. The proper method is for brackets to contain spacing within, and operators to contain spacing around. In some instances different combinations work; however, the following is intended to be a universal example.
if [ "$1" == "something" ]; then ## GOOD
if [ "$1" = "something" ]; then ## GOOD
if [ "$1"="something" ]; then ## BAD (operator spacing)
if ["$1" == "something"]; then ## BAD (bracket spacing)
Also, note double brackets are handled slightly differently compared to single brackets ...
if [[ $a == z* ]]; then # True if $a starts with a "z" (pattern matching).
if [[ $a == "z*" ]]; then # True if $a is equal to z* (literal matching).
if [ $a == z* ]; then # File globbing and word splitting take place.
if [ "$a" == "z*" ]; then # True if $a is equal to z* (literal matching).
It seems that you are looking to parse commandline arguments into your bash script. I have searched for this recently myself. I came across the following which I think will assist you in parsing the arguments:
http://rsalveti.wordpress.com/2007/04/03/bash-parsing-arguments-with-getopts/
I added the snippet below as a tl;dr
#using : after a switch variable means it requires some input (ie, t: requires something after t to validate while h requires nothing.
while getopts “ht:r:p:v” OPTION
do
case $OPTION in
h)
usage
exit 1
;;
t)
TEST=$OPTARG
;;
r)
SERVER=$OPTARG
;;
p)
PASSWD=$OPTARG
;;
v)
VERBOSE=1
;;
?)
usage
exit
;;
esac
done
if [[ -z $TEST ]] || [[ -z $SERVER ]] || [[ -z $PASSWD ]]
then
usage
exit 1
fi
./script.sh -t test -r server -p password -v

Resources