bash, 2 clause if statement - bash

if [[ $GreaterThanTwenty==1 && $LessThanThirty==1 ]]
then
echo "within limits"
else
echo "Outside limits"
fi
echo $GreaterThanTwenty
echo $LessThanThirty
Why is Within limits triggered even though the echoes show that at this point LessThanThirty is actually 0?

You should compare arithmetic values using one of these: -eq, -ne, -lt, -le, -gt or -ge, meaning equal, not equal, less than, less than or equal, greater than and greater than or equal, respectively.
Reference: http://www.ibm.com/developerworks/library/l-bash-test/index.html

Related

Strange comparison results

I have some bash issues:
This is expected:
[[ 0 -eq 0 ]] && echo "equal!"
> equal!
This is not:
[[ "" -eq 0 ]] && echo "equal!"
> equal!
Why is "" equal to 0?
How can I check for numeric equality?
This is because Bash tries hard to convert whatever you put into both sides of -eq into integers, and will convert the empty string to zero. The conversions are far from trivial. Here's how I expect the code parses numbers, without actually having read it:
$ [[ x -eq 0 ]] && echo "equal!"
equal!
After Bash detects a numeric context (-eq) it starts creating a number from zero on the left side, scans and finds x, discards it, scans and finds whitespace, and therefore considers the left side zero. Hence the above is equivalent to [[ 0 -eq 0 ]]
$ [[ 0x10 -eq 16 ]] && echo "equal!"
equal!
Starting from zero again, Bash sees a zero (before the "x") and goes into "alternate base" mode, finds an "x" and goes into hexadecimal mode, and reads the remaining digits ("10") as a hexadecimal number.
$ [[ 00x10 -eq 16 ]] && echo "equal!"
bash: [[: 00x10: value too great for base (error token is "00x10")
After going into "alternate base" mode after seeing a zero Bash sees a number (the second zero), and therefore goes into octal mode. x is considered a "numeric character" in this mode because it can be used in higher bases, but "x" is not a valid octal digit, so it fails.
See the Bash manual for more.

bash if statement doesn't work as expected

I'm new in bash scripting.
I use this code:
#!/bin/bash
count=0
ende="100"
while true; do
out=$(php '/var/www/testsh.php' $count)
if [ "$out"!=="$ende" ]
then
echo "$out i break"
break
fi
echo "sleeping"
sleep 10
((count++))
done
In my PHP: echo '100';
./test.sh gives me:
100 i break
but it should output sleeping till $out is not 100
"$out"!=="$ende" gets substituted into 100!==100, which is a non-empty string, which [ evaluate the same as -n 100!==100 - true, because it is a non-zero string.
"$out" != "$ende" would get substituted into 100 != 100 which is an operator with two operands, and evaluates to false (as it compares two strings).
In a different scenario, != might produce a logical error, since it compares operands as strings. Fortunately, equality of strings in your case is identical to equality of integers (for which you would use -ne), but don't count for it always to be the case.
In [, operators need their space
In [, there's no such thing as !==
For integers, use -eq, -ne, -lt, -le, -gt, -ge
Also, you might like seq:
for count in $(seq 100)
do
# will happen 100 times, with `count` from `0` to `99`
done

Why does a string equal zero in bash test

I have an array which I am using to generate a list which a user can choose from made like this.
list=(a b c d)
n=0
for x in ${list[#]}
do echo $n\)$x
n=$((n++)
done
read -p "Pick an item:" choice
I want to allow only valid options to be chosen so I am checking like this.
if [[ $choice -gt ${#list[#]} && $choice -lt -1 ]]
then ...
else
echo "not a valid choice"
The issue I am having is all strings evaluate at equal to zero. ie [[ "I am a duck" -eq 0 ]] is True, as is (( "I am a duck" == 0 )). Is there a way to make all string and number comparison evaluate to false? I know I can check for a string with [[ $choice =~ [A-Za-z]+ ]], but I am wondering if there is a way without regular expressions?
EDIT
Sorry, I should have tested the "I am a duck" statement before I put it down. It doesn't like the spaces. However, "I_am_a_duck" does evaluate to 0. This explained by chepner below.
-gt, because it is intended to compare integers, triggers the same behavior for strings as seen in an arithmetic expression: the string is treated as the name of a parameter, and that parameter is expanded (repeat the process if necessary) until you get an integer. If there is no parameter by that name, 0 is substituted.
That said, you could weasel your way out of the problem by number your items starting at one and using
if (( choice < 1 || choice > ${#list[#]} )); then
echo "not a valid choice"
since now any non-integer inputs will be treated as 0, which is indeed less than the lower limit of 1.
I would use select for this and not deal with behaviour of strings in arithmetic contexts (as explained in chepner's answer) at all:
list=(a b c d)
PS3='Pick an item: '
select opt in "${list[#]}"; do
case $opt in
[abcd]) echo "Choice: $opt ($REPLY)" ;;
*) echo "Illegal choice" ;;
esac
done
This will keep looping; to continue after a valid selection, there has to be a break somewhere. The main benefit is select taking care of invalid inputs for you, and you don't have to build the menu yourself.

why does float comparison works without bc in a AND_IF or "&&" command

The only way I could find out to compare floats in shell is:
A=12.3
B=12.2
if [ $(bc <<< "$B <= $A") -eq 1 ]
Direct comparison, as far as I know, doesn't happen.
but strangely the following code compares floats without bc:
A=13.7
B=13.2
[[ $A > $B ]] && echo "A is greater than B"
[[ $A < $B ]] && echo "A is less than B"
This returns:
A is greater than B
As far as I know && executes the second command only and only if the first command returns with an exit status zero.
However, as suggested by Pixel Chemist in the comments if we attempt to use negative numbers in the second methods, it doesn't work and gives the opposite results.
Can someone please explain how is the second method working without bc.

Bash Script "integer expression expected" , use of floats in bash instead of other language [duplicate]

This question already has answers here:
How can I compare two floating point numbers in Bash?
(22 answers)
Closed 6 years ago.
I am new to bash scripting. My code is :
MK=M
SM=1.4
if [[ $MK == "M" ]]
then
if [ $SM -gt 1.3 ]
then
echo "Greater than 1.3M"
else
echo "Less than 1.3M"
fi
else
echo "Not yet M...."
fi
Reply:
/tmp/tmp.sh: line 6: [: 1.4: integer expression expected
Less than 1.3M
What am i doing wrong ?
Here's what man bash says:
arg1 OP arg2 ... Arg1 and arg2 may be positive or negative integers.
You seem to be trying to compare floating point numbers.
It's ultimately because bash is not terribly patient when it comes to floating point numbers. In very simple terms here, I would suggest you do one of two things:
It looks like you are trying to determine if something is larger than 1.3 Mb or not, is this correct? If this is the case, then leave everything the way you have it, and just use Kb for $sm and the compare
like this:
#/bin/bash
mk="p"
km="p"
sm="1400"
ms="1300"
if [[ $mk == $km ]]
then
if [ $sm > $ms ]
then
echo "Greater than 1.3M"
else
echo "Less than 1.3M"
fi
else
echo "Not yet M...."
fi
or
Use bc for the calculation of the floating point numbers...
# /bin/bash
mk="p"
km="p"
sm="1.4"
ms="1.3"
if [ $(echo "$mk == $km" | bc) ]
then
if [ $(echo "$sm > $ms" | bc) ]
then
echo "Greater than 1.3M"
else
echo "Less than 1.3M"
fi
else
echo "Not yet M...."
fi
One more thing to note here, is that, as you can see from my code, I have primed new variables with the data, rather than using raw letters and numbers in boolean and compare operations, which can have some genuinely unexpected results. Also, while they may work in some conditions, temporarily, bash prefers all variable names to be in lower-case. Let me know if you have any questions.. However, I have tested both code chunks, and they both work fine.

Resources