So i have a piece of bash code here and i am beginning scripting. Anyway, so what’s happening is I am making a calculator for a lab assignment, and assume that I have three strings of data (because bash is all strings). Stored in three variables “a” for add and 1 and 2 for the numbers.
So I started the code below where i echo print out the three variables and i can see them in there correctly. I am confused when the first one named $OP is correctly filled with a value of “a” why the negative if statement just below is entering itself instead of continuing to the else or elif. Proof of this when $OP variable is “a” is the program is printing “…must enter either operation of add, subtract, divide” instead of not being pushed forth to the elif or else part, not sure how i am going to structure that yet. Why is sending a,s,d, or m still evaluating the if condition true instead of skipping to the else?
#Main Script
#Request three arguments from the user
RC=0
read -p "enter s for subtract, a for add, d for divide or m for multiply followed by
the two numbers to work with: " OP NUM1 NUM2
#Verify that the user has entered three arguments and that they are of the correct type
numArgs $OP $NUM1 $NUM2
echo $OP;
echo $NUM1;
echo $NUM2
#Secondly verify they are of the correct types.
if [[ $OP != "a" || $OP != "d" || $OP != "m" || $OP != "s" ]] ; then
echo "You must supply an operation of either add, subtract, multiply or divide."
exit
elif [[ $NUM1 =~ .[0-9] && $NUM2 =~ .[0-9] ]] ; then
#call functions to do arithmetic
add $NUM1 $NUM2
fi
4
Your code is equivalent to:
IF I do not have a car OR I do not have a bicycle THEN
I must walk to work
ELSE
I can ride to work
ENDIF
when you were trying to write:
IF I do not have a car AND I do not have a bicycle THEN
I must walk to work
ELSE
I can ride to work
ENDIF
Always try to avoid using negative constructs like !
, though, as negatives make code harder to understand (even by the author) and introduce the possibility of double-negatives which are extremely difficult to understand. If you don’t use negatives then you can’t have double negatives. The above could be written:
IF I have a car OR I have a bicycle THEN
I can ride to work
ELSE
I must walk to work
ENDIF
and it becomes immediately clearer and easier to maintain.
In your code:
if [[ $OP != "a" || $OP != "d" || $OP != "m" || $OP != "s" ]] ; then
echo "You must supply an operation of either add, subtract, multiply or divide."
exit
elif [[ $NUM1 =~ .[0-9] && $NUM2 =~ .[0-9] ]] ; then
#call functions to do arithmetic
add $NUM1 $NUM2
fi
try to state what the condition is under which you execute the else
block. The answer is:
It is NOT true that $OP does NOT have the value “a”, etc.
i.e. it’s a double negative.
The code you’re trying to write, using positive logic would be:
if [[ $OP == "a" || $OP == "d" || $OP == "m" || $OP == "s" ]] ; then
if [[ $NUM1 =~ .[0-9] && $NUM2 =~ .[0-9] ]] ; then
#call functions to do arithmetic
add "$NUM1" "$NUM2"
fi
else
echo "You must supply an operation of either add, subtract, multiply or divide."
exit
fi
and if you don’t want the if
s nested you could write it as:
if [[ $OP == "a" || $OP == "d" || $OP == "m" || $OP == "s" ]] ; then
:
else
echo "You must supply an operation of either add, subtract, multiply or divide."
exit
fi
if [[ $NUM1 =~ .[0-9] && $NUM2 =~ .[0-9] ]] ; then
#call functions to do arithmetic
add "$NUM1" "$NUM2"
fi
or any of multiple alternatives that still avoid negative logic.
For every string S you can imagine, S != a || S != b
will be true. There is no string which can be unequal to the string a AND unequal to the string b at the same time.
You could try an extglob syntax/feature inside the [[ ]]
if [[ "$OP" != @(a|d|m|s) ]]; then
printf 'You must supply an operation if either add, subtract multiply or divide.n' >&2
exit
fi
if [[ "$NUM1" =~ .[0-9] && "$NUM2" =~ .[0-9] ]]; then
add "$NUM1" "$NUM2"
fi
- See I want to check if [[ $var == foo || $var == bar || $var == more ]] without repeating $var n times.