I am not sure about this comparison i am doing:
if [ "$exit_status" -eq 0 ];then
#some statements
fi
is this correct way of comparing numbers or quotes make the variable exit_status
a string
to be compared with 0.I don't know if this could fail in some scenario.
-
It is correct but if you are using Bash you should use ((...)). It is an arithmetic command, which returns an exit status of 0 if the expression is nonzero, or 1 if the expression is zero. Also used as a synonym for "let", if side effects (assignments) are needed. See Arithmetic Expression.Rany Albeg Wein– Rany Albeg Wein2013年04月28日 14:51:17 +00:00Commented Apr 28, 2013 at 14:51
3 Answers 3
Yes, it is correct.
Quotes in shells are for different purpose than in other languages. See this answer for more details.
In shell, quotes are used to prevent the shell to treat some characters specially and to prevent some operations that the shell would otherwise perform upon some types of expansion (like in this case variable expansion).
Typically, in this case, you want "$exit_status"
to be expanded to one argument to the [
command that is the content of that varaible, so you need the quotes.
[ "$exit_status" -eq 0 ]
is correct if $exit_status only contains digits, and you could just as well remove the quotes (as long as IFS doesn't contain digits).
If x is empty or unset, [ "$x" -eq 6 ]
results in an error but [[ "$x" -eq 6 ]]
doesn't:
$ x=; [ "$x" -eq 6 ]
-bash: [: : integer expression expected
$ unset x; [ "$x" -eq 6 ]
-bash: [: : integer expression expected
$ x=; [[ "$x" -eq 6 ]]
$ unset x; [[ "$x" -eq 6 ]]
$
Arithmetic operators strip whitespace:
$ [ '6 ' -eq $'\n\t6' ]; echo $?
0
Inside [[ the operands of arithmetic operators are arithmetic expressions, so for example [[ 4 -eq 2+2 ]]
is true. Numbers that start with 0 are treated as octal numbers:
$ [[ 010 -eq 8 ]]; echo $?
0
$ [ 010 -eq 8 ]; echo $?
1
I often use = / == even for comparing integers. = and == are equivalent in bash inside both [[ and [. == and [[ are not defined by POSIX.
Word splitting and pathname expansion are not performed inside [[. [[ $x = $y ]]
treats y as a pattern but [[ $x = "$y" ]]
treats y literally:
$ x=44; y='4*'
$ [[ $x = $y ]]; echo $?
0
$ [[ $x = "$y" ]]; echo $?
1
-
1More precisely,
[[...]]
's-eq
compares two arithmetic expressions, while[
's compares decimal integer constants only (but you can do[ "$((6+6))" -eq "$((0xc))" ]
with the standard syntax for[[ 6+6 -eq 0xc ]]
). While you're at using non-standardksh
extensions, it's better to do(( exp1 == exp2 ))
to do arithmetic comparison. Note that[[ "1 + 1" -eq "4 - 2" ]]
is not equivalent to[[ 1 + 1 -eq 4 - 2 ]]
(which would be a syntax error), and[[ $x*2 -eq $y*3 ]]
is not the same as[[ x*2 -eq y*3 ]]
(for instance in cases where$x
is1+2
).Stéphane Chazelas– Stéphane Chazelas2013年04月30日 11:31:12 +00:00Commented Apr 30, 2013 at 11:31
Quoting numbers is of little use though. If the parameter value is a number then the quotes don't change anything and if it is not then the if is going to fail anyway. OK, not in every case:
exit_status="a = a -o 0"; [ "$exit_status" -eq 0 ] # returns false
exit_status="a = a -o 0"; [ $exit_status -eq 0 ] # returns true
This is due to [
being a bash builtin but nonetheless a simple command whereas [[
is a compound command that changes command line parsing.
-
2You've got it backward. It's not quoting numbers that is of little use. Not quoting a variable (even if you know for sure contains only decimal digits) still asks the shell to perform word splitting, filename generation and empty removal on it, and it would still be a problem if
$IFS
does happen to contain digits. Quoting variables should always be the default. Only remove the quotes if you have a good reason to, like in the rare cases where you do need word splitting or filename generation.Stéphane Chazelas– Stéphane Chazelas2013年04月24日 13:33:44 +00:00Commented Apr 24, 2013 at 13:33