bash handle both starts with non-zero and zero value in if - bash

I need to compare two integer values and here is the if condition,
if [[ $VAL -ge 1000 ]] ; then
#do something
fi
But the problem is when it tries to compare with an integer value 010 got the error saying
-bash: 01: value too great for base (error token is "01")
I fixed this issue by using $VAL#0 in if condition.
But still getting same kind of issue with it tries to compare integer value 0010 and it fixed with 10#${VAL}.
The problem with proper integer values like 523 and getting below error,
[[: #10523: syntax error: operand expected (error token is "#10523")
Not sure how to make the if statement works with all the cases.
Update (Solution):
Found the fix.
VAL=$((10#$VAL))
Whatever value this will change it to decimal and reassign it to the same variable.

I think there's something not quite right with your example. 010 will not give a base error, but e.g. 090 will. That's because numbers with a leading zero are assumed to be octal.
To manually set the base, prefix the number with 10#:
$ if [[ 100 -gt 090 ]]; then echo t; else echo f; fi
bash: [[: 090: value too great for base (error token is "090")
f
$ if [[ 100 -gt 10#090 ]]; then echo t; else echo f; fi
t
For your case, that means you should use:
if [[ "10#$VAL" -ge 1000 ]] ; then
#do something
fi

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.

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.

if condition in shell script - error token - digits 8 and 9 in date output

I have the following shell script:
prodStartTime="213000"
prodEndTime="235959"
currentTime=`date +"%H%M%S"`
if [[ ${currentTime} -ge ${prodStartTime#0} && ${currentTime} -le ${prodEndTime#0} ]];
then
echo "Something .........."
else
echo "Else part Something .........."
fi
Getting Error
"line 5: prodStartTime: 043058: value too great for base (error token is "043058")"
This error occurs when 8 or 9 are present in hours or minutes.
Example:
(error token is "043058")
(error token is "043059")
(error token is "043850")
(error token is "043901")
It is because time strings with leading zero are being interpreted as octal numbers instead of decimal.
To prevent this, change your date assignment this way which strips off leading zeros if any:
currentTime=`date +"%-H%M%S"`
Read more about zero padding in date here: Removing leading zeros from DATE
Just make sure Bash understands your number in radix 10 as follows:
currentTime=$(( 10#$(date +"%H%M%S") ))
The 10# prefix forces radix 10. See the end of this paragraph of the reference manual.
I think the simplest and clearest fix is to use string comparison rather than numeric comparison:
prodStartTime=213000
prodEndTime=235959
currentTime="$(date +%H%M%S)"
if [[ $currentTime > $prodStartTime && $currentTime < $prodEndTime ]] ; then
echo "Something .........."
else
echo "Else part Something .........."
fi
Could you change one of these;
currentTime=`date +"%k%M%S"`
or
currentTime=`date +"_H%M%S"`
man date :
%k hour, space padded ( 0..23); same as %_H
%H hour (00..23)

Bash in if check integer

I have created a script in bash. I need to check if take 0 number then ignore this, but if take some value then I need to calculate based on the value given and print the result.
Here is an example:
if [ "$max_users_conn" -ne "0" ]; then
let "percentage="$process_list"*100/"$max_users_conn""
echo "$percentage"
fi
However, when I run the code, I receive the following error:
./mysql_conn.sh: line 14: [: 0 10: integer expression expected
./mysql_conn.sh: line 14: [: 0 10: integer expression expected
./mysql_conn.sh: line 14: [: 5 5: integer expression expected 0 20
I also tried to run it like this:
if [ "$max_users_conn" != "0" ]; then
let "percentage="$process_list"*100/"$max_users_conn""
echo "$percentage"
fi
But this gives a different error:
./mysql_conn.sh: line 15: let: percentage=4*100/0: division by 0
(error token is "0")
./mysql_conn.sh: line 15: let: percentage=4*100/0: division by 0
(error token is "0")
0 0 20
Bash does not allow you math expressions like other languages do, you need to use the $(( ... )) operator for this. However, this operator gives you only operations base on integers if you supply integers: echo $((2/4)) # => 0. If you do not care about fractions, though, it will help you. If you need fractions, utilize bc like anubhava showed in his answer.
Additionally, you should check that $max_users_conn actually contains a value.
So, rewrite your snipped to look like this:
if [ -n "$max_users_conn" -a "$max_users_conn" -ne 0 ]; then
percentage=$(( $process_list * 100 / $max_users_conn))
echo "$percentage"
fi
test "$a" -ne 0 checks for numeric values, while test "$a" != "$b" checks for string equivalence.
In BASH you can do:
if [[ $max_users_conn -ne 0 ]]; then
percentage=$((process_list * 100 / max_users_conn))
echo "$percentage"
fi
but keep in mind that BASH doesn't support floating point maths and you will get an integer value returned.
To get decimal number returned use this bc command above.
percentage=$(bc -l <<< "scale=2; $process_list * 100 / max_users_conn")

Unary operator expected in Bash

I've seen questions regarding the same issue, but all of them are about strings. How about integers? Why am I getting the "unary operator expected" error?
if [ $(date +%k%M) -ge ${!BLOCK1FRAN} ] ; then whatever ; fi
You are using indirection. If the variable ${BLOCK1FRAN} points to an empty variable, you'll get the error message. Make sure that the variable pointed by ${BLOCK1FRAN} contains a valid numeric value.
If you want an empty string and nonnumeric values to be evaluated as zero (0), use the following syntax.
if [[ $(date +%k%M) -ge ${!BLOCK1FRAN} ]]; then whatever ; fi
It looks good to me. Are you sure you've set BLOCK1FRAN correctly?
whatever() { echo "it works"; }
foo=42
BLOCK1FRAN=foo
if [ $(date +%k%M) -ge ${!BLOCK1FRAN} ] ; then whatever ; fi
it works

Resources