Is there any major difference when comparing a variable as a string or as an int
Solution 1
Yep, lots of differences. For instance, =
checks for exact string equality, but -eq
evaluates both expressions arithmetically before checking for equality:
$ [ " 1 " -eq 1 ] && echo equal || echo not
equal
$ [ " 1 " = 1 ] && echo equal || echo not
not
$ [ +1 -eq 1 ] && echo equal || echo not
equal
$ [ +1 = 1 ] && echo equal || echo not
not
$ [ "0+1" -eq 1 ] && echo equal || echo not
equal
$ [ "0+1" = 1 ] && echo equal || echo not
not
Also, the empty string happens to be numerically equal to zero:
$ [ "" -eq 0 ] && echo equal || echo not
equal
$ [ "" = 0 ] && echo equal || echo not
not
And a whole other class of differences appears when you bring the comparison operators in - considering <
vs -lt
, for instance:
$ [[ 2 -lt 10 ]] && echo less || echo not
less
$ [[ 2 < 10 ]] && echo less || echo not
not
This is because the string "2" is alphabetically after the string "10" (since 1 comes before 2), but the number "2" is numerically less than the number "10".
Solution 2
Integer vs. string comparison becomes most significant when you are comparing greater or lesser than:
#!/bin/bash
eleven=11
nine=9
[[ $nine < $eleven ]] && echo string # fail
[[ "$nine" -lt "$eleven" ]] && echo integer # pass
The first one fails because 9 comes after 11 when sorted lexicographically.
Note that using quotes does not determine whether you are comparing strings or numbers, the operator does. You can add or remove the quotes above, it does not make any difference. Bash catches undefined variables within double brackets, so quotes are not necessary. Using quotes with single brackets for numerical tests won't save you since:
[ "" -lt 11 ]
is an error anyway ("integer expression required"). Quotes are an effective safeguard with string comparisons in single brackets:
[ "" \< 11 ]
Note within double brackets, ""
will -eq 0
but not == 0
.
Solution 3
In addition to what has been said.
Comparing for equality is faster with numbers, although in shell scripting it is rare that you need fast calculation.
$ b=234
$ time for ((a=1;a<1000000;a++)); do [[ $b = "234" ]]; done
real 0m13.008s
user 0m12.677s
sys 0m0.312s
$ time for ((a=1;a<1000000;a++)); do [[ $b -eq 234 ]]; done
real 0m10.266s
user 0m9.657s
sys 0m0.572s
Related videos on Youtube
user1845506
Updated on September 18, 2022Comments
-
user1845506 almost 2 years
Out of curiosity, when doing a bash variable comparison (its value being an
integer
) it's possible to test it against some predefined value either declared as anint
or as astring
.Sample script:
#!/bin/bash f1() { [ "$1" == "1" ] && echo "$FUNCNAME: \"1\" compared as string" } f2() { [[ "$1" -eq 1 ]] && echo "$FUNCNAME: \"1\" compared as int" } f1 $1 f2 $1
Output:
$ ./param.sh 1 f1: "1" compared as string f2: "1" compared as int
and
$ ./param.sh blah $
Both functions behave the same way, and so I'm wondering if there's a preferred way when checking an integer variable? I would go for checking
int
versusint
as it's more strict but I wonder if there are any draw backs doing it withstring
?In this case,
f2()
is also more strict about the comparison, i.e. passing a decimal value will break it, whereasf1()
will take it no problem. -
godlygeek almost 10 yearsConsidering that they do different things, I'd say the performance is irrelevant - you need to use the one that does what you want.
-
Angel Todorov almost 10 yearsIn bash, it's not strictly necessary to quote variables within double brackets: the builtin
[[
is smart enough to remember where the variables are, and it won't get fooled by empty variables. Single brackets ([
) do not have this feature, and require quotes. -
Emmanuel almost 10 years@godlygeek Equality comparison of a variable can be achieved both way. "-eq" is faster.
-
goldilocks almost 10 years@glennjackman Had not noticed that.
[[ -lt 11 ]]
is an error, butnothing=; [[ $nothing -lt 11 ]]
is not. I've reworked the last paragraph a bit. -
godlygeek almost 10 yearsThey test for different definitions of equality. If you want to answer the question "Does this variable hold the exact string 123", you can only use
=
, since using-eq
would match for "+123" as well. If you wanted to know "Does this variable, when evaluated as an arithmetic expression, compare equal to 123", you could only use-eq
. The only time I can see where a programmer wouldn't care which definition of equality was used is when he knows that the contents of the variable are constrained to a particular pattern ahead of time. -
Emmanuel almost 10 years@godlygeek interesting, the question was about comparing equality of numbers as if they were strings, does it fits the case of variables constrained ahead of time to a particular pattern ?
-
godlygeek almost 10 yearsYour example (
b=234
) fits that pattern - you know it's not +234 or " 234 " or "233+1", since you assigned it yourself, so you know that it comparing it as a string and as a number are equally valid. But the OP's script, since it takes input as a command line argument, doesn't have that constraint - consider calling it as./param.sh 0+1
or./param.sh " 1"
-
phemmer almost 10 yearsDon't forget there's also
(( ... ))
for numeric operations.(( " 1 " == 1 )) && echo yes || echo no
results inyes