Search code examples
bashcompareoperators

What bash compare operator always works for string and numeric comparisons


Migrated to Almalinux 9 from CentOS 7 I've written a simplest Bash script to control quantity of inotifywait processes (must be 11) - but I was very surprised the results depending on compare operator used.

(BASH - GNU bash, version 5.1.8(1)-release (x86_64-redhat-linux-gnu))

#!/bin/bash
itf=$(ps aux | grep [i]notify | wc -l); 
status=$(mysql -uroot -N -e 'SELECT status FROM db.table WHERE filename LIKE "rates.xml"');
echo "$itf";  # correct value - 11
echo "$status";  # correct value - OK
printf "First compare numeric\n"
if [[ "itf" -eq 11 ]] ; then 
echo "OK - all 11 inotifywait processes run";
else
printf  "Just $itf inotifywait processes running of 11\n";
fi
printf "Second compare string just experiment\n"
if [[ "$status" != "OK" ]]; then
echo STATUS BAD ;
else
echo STATUS GOOD ;
fi
exit ;
    sh

I do not see any errors in coding above - but result for count is wrong. In spite of bash counted 11 processes (as should be) - it shows negative result

Just 11 inotifywait processes running of 11

But when I change compare operator from

if [[ "itf" = 11 ]] ; then 

to

if [[ "itf" -eq 11 ]] ; then 

then I have positive result as should be

OK - all 11 inotifywait processes run

At the same time it seems NO MATTER what operator to use when compare strings. I was tested both

if [[ "$status" != "OK" ]]; then
if [[ "$status" -ne "OK" ]]; then

both cases we have correct result

STATUS GOOD

No matter run script as SH or BASH.

My question is - should we ALWAYS use in bashes the "text" compare operators like "-ne", "-eq" etc - because they are UNIVERSAL for all kind of comparisons, string or numeric or whatever else ? Thx in advance for your opinions,


Solution

  • In Bash there are only strings.

    -ne -eq compare numbers, or in the context of [[, arithmetic expressions.

    In arithmetic expression, string that is not a variable is replaced by 0.

    $ if [[ "OK" -eq 0 ]]; then echo true; fi
    true
    $ if [[ "literally_anything" -eq 0 ]]; then echo true; fi
    true
    $ if [[ "literally_anything" -eq "something_completely_else" ]]; then echo true; fi
    true
    $ literally_anything=1
    $ something_completely_else=2
    $ if [[ "literally_anything" -eq "something_completely_else" ]]; then echo true; else echo false; fi
    false
    
     if [[ "itf" -eq 11 ]] ; then 
    

    itf is a variable. -eq evaluates itf and expands it.

    You meant to write if [[ "$itf" = 11 ]] ; then to compare strings in your code.

    It might be more readable to if ((itf == 11)).

     if [[ "$status" -ne "OK" ]]; then
    

    $status expands to some text. This text happens not to be a variable. So it becomes 0. OK is also not a variable, so it becomes 0.

    What bash compare operator always works for string and numeric comparisons

    None. = compares strings. -ne -eq compare numbers.