Bash Equality Operators ( == , -eq )
Can someone please explain the difference between -eq
and ==
in bash scripting?
Is there any difference between the following?
[ $a -eq $b ]
and [ $a == $b ]
Is it simply that ==
is only used when the variables contain numbers?
bash
add a comment |
Can someone please explain the difference between -eq
and ==
in bash scripting?
Is there any difference between the following?
[ $a -eq $b ]
and [ $a == $b ]
Is it simply that ==
is only used when the variables contain numbers?
bash
add a comment |
Can someone please explain the difference between -eq
and ==
in bash scripting?
Is there any difference between the following?
[ $a -eq $b ]
and [ $a == $b ]
Is it simply that ==
is only used when the variables contain numbers?
bash
Can someone please explain the difference between -eq
and ==
in bash scripting?
Is there any difference between the following?
[ $a -eq $b ]
and [ $a == $b ]
Is it simply that ==
is only used when the variables contain numbers?
bash
bash
edited Oct 25 '17 at 21:24
guaka
10.5k74481
10.5k74481
asked Dec 8 '13 at 3:29
Victor BrunellVictor Brunell
1,23541835
1,23541835
add a comment |
add a comment |
4 Answers
4
active
oldest
votes
It's the other way around: ==
is for string comparisons, -eq
is for numeric ones. -eq
is in the same family as -lt
, -le
, -gt
, -ge
, and -ne
, if that helps you remember which is which.
$ [ a == a ]; echo $?
0
$ [ a -eq a ]; echo $?
-bash: [: a: integer expression expected
2
==
is a bash-ism. The POSIX form is =
. If portability to non-bash shells is important, use =
.
1
Even if portability is not an immediate concern, I see no benefit from using the nonportable longer Bash-only form.
– tripleee
Nov 19 '18 at 7:56
add a comment |
==
is a bash-specific alias for =
and it performs a string (lexical) comparison instead of a numeric comparison. eq
being a numeric comparison of course.
Finally, I usually prefer to use the form if [ "$a" == "$b" ]
8
Using==
here is bad form, as only=
is specified by POSIX.
– Charles Duffy
Oct 19 '15 at 5:45
5
If you really insist to use==
then put it in between[[
and]]
. (And make sure that the first line of your script specifies to use/bin/bash
.)
– holgero
Dec 21 '15 at 20:28
add a comment |
It depends on the Test Construct around the operator. Your options are double parenthesis, double braces, single braces, or test
If you use ((...)), you are testing arithmetic equity with ==
as in C:
$ (( 1==1 )); echo $?
0
$ (( 1==2 )); echo $?
1
(Note: 0
means true
in the Unix sense and non zero is a failed test)
Using -eq
inside of double parenthesis is a syntax error.
If you are using [...] (or single brace) or [[...]] (or double brace), or test
you can use one of -eq, -ne, -lt, -le, -gt, or -ge as an arithmetic comparison.
$ [ 1 -eq 1 ]; echo $?
0
$ [ 1 -eq 2 ]; echo $?
1
$ test 1 -eq 1; echo $?
0
The ==
inside of single or double braces (or test
command) is one of the string comparison operators:
$ [[ "abc" == "abc" ]]; echo $?
0
$ [[ "abc" == "ABC" ]]; echo $?
1
As a string operator, =
is equivalent to ==
and note the whitespace around =
or ==
its required.
While you can do [[ 1 == 1 ]]
or [[ $(( 1+1 )) == 2 ]]
it is testing the string equality -- not the arithmetic equality.
So -eq
produces the result probably expected that the integer value of 1+1
is equal to 2
even though the RH is a string and has a trailing space:
$ [[ $(( 1+1 )) -eq "2 " ]]; echo $?
0
While a string comparison of the same picks up the trailing space and therefor the string comparison fails:
$ [[ $(( 1+1 )) == "2 " ]]; echo $?
1
And a mistaken string comparison can produce the complete wrong answer. '10' is lexicographically less than '2', so a string comparison returns true
or 0
. So many are bitten by this bug:
$ [[ 10 < 2 ]]; echo $?
0
vs the correct test for 10 being arithmetically less than 2:
$ [[ 10 -lt 2 ]]; echo $?
1
In comments, there is a question of the technical reason using the integer -eq
on strings returns True for strings that are not the same:
$ [[ "yes" -eq "no" ]]; echo $?
0
The reason is that Bash is untyped. The -eq
causes the strings to be interpreted as integers if possible including base conversion:
$ [[ "0x10" -eq 16 ]]; echo $?
0
$ [[ "010" -eq 8 ]]; echo $?
0
$ [[ "100" -eq 100 ]]; echo $?
0
And 0
if Bash thinks it is just a string:
$ [[ "yes" -eq 0 ]]; echo $?
0
$ [[ "yes" -eq 1 ]]; echo $?
1
So [[ "yes" -eq "no" ]]
is equivalent to [[ 0 -eq 0 ]]
Last note: Many of the Bash specific extensions to the Test Constructs are not POSIX and therefore will fail in other shells. Other shells generally do not support [[...]]
and ((...))
or ==
.
I'm curious about the technical reason for[[ "yes" -eq "no" ]]
returning True. How does bash coerce these strings to integer values that can be compared? ;-)
– odony
May 11 '17 at 14:42
2
Bash variables are untyped so[[ "yes" -eq "no" ]]
is equivalent to[[ "yes" -eq 0 ]]
or[[ "yes" -eq "any_noninteger_string" ]]
-- All True. The-eq
forces integer comparison. The"yes"
is interpreted as a integer0
; the comparison is True if the other integer is either0
or the string result is0
.
– dawg
May 12 '17 at 19:55
@odony: See update
– dawg
May 13 '17 at 15:05
add a comment |
Guys: Several answers show dangerous examples. OP's example [ $a == $b ]
specifically used unquoted variable substitution (as of Oct '17 edit). For [...]
that is safe for string equality.
But if you're going to enumerate alternatives like [[...]]
, you must inform also that the right-hand-side must be quoted. If not quoted, it is a pattern match! (From bash man page: "Any part of the pattern may be quoted to force it to be matched as a string.").
Here in bash, the two statements yielding "yes" are pattern matching, other three are string equality:
$ rht="A*"
$ lft="AB"
$ [ $lft = $rht ] && echo yes
$ [ $lft == $rht ] && echo yes
$ [[ $lft = $rht ]] && echo yes
yes
$ [[ $lft == $rht ]] && echo yes
yes
$ [[ $lft == "$rht" ]] && echo yes
$
That's a dangerous gotcha, thanks for posting it!
– joanis
Jan 16 at 21:24
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f20449543%2fbash-equality-operators-eq%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
It's the other way around: ==
is for string comparisons, -eq
is for numeric ones. -eq
is in the same family as -lt
, -le
, -gt
, -ge
, and -ne
, if that helps you remember which is which.
$ [ a == a ]; echo $?
0
$ [ a -eq a ]; echo $?
-bash: [: a: integer expression expected
2
==
is a bash-ism. The POSIX form is =
. If portability to non-bash shells is important, use =
.
1
Even if portability is not an immediate concern, I see no benefit from using the nonportable longer Bash-only form.
– tripleee
Nov 19 '18 at 7:56
add a comment |
It's the other way around: ==
is for string comparisons, -eq
is for numeric ones. -eq
is in the same family as -lt
, -le
, -gt
, -ge
, and -ne
, if that helps you remember which is which.
$ [ a == a ]; echo $?
0
$ [ a -eq a ]; echo $?
-bash: [: a: integer expression expected
2
==
is a bash-ism. The POSIX form is =
. If portability to non-bash shells is important, use =
.
1
Even if portability is not an immediate concern, I see no benefit from using the nonportable longer Bash-only form.
– tripleee
Nov 19 '18 at 7:56
add a comment |
It's the other way around: ==
is for string comparisons, -eq
is for numeric ones. -eq
is in the same family as -lt
, -le
, -gt
, -ge
, and -ne
, if that helps you remember which is which.
$ [ a == a ]; echo $?
0
$ [ a -eq a ]; echo $?
-bash: [: a: integer expression expected
2
==
is a bash-ism. The POSIX form is =
. If portability to non-bash shells is important, use =
.
It's the other way around: ==
is for string comparisons, -eq
is for numeric ones. -eq
is in the same family as -lt
, -le
, -gt
, -ge
, and -ne
, if that helps you remember which is which.
$ [ a == a ]; echo $?
0
$ [ a -eq a ]; echo $?
-bash: [: a: integer expression expected
2
==
is a bash-ism. The POSIX form is =
. If portability to non-bash shells is important, use =
.
edited Nov 4 '16 at 21:21
mklement0
129k20242271
129k20242271
answered Dec 8 '13 at 3:31
John KugelmanJohn Kugelman
241k53401455
241k53401455
1
Even if portability is not an immediate concern, I see no benefit from using the nonportable longer Bash-only form.
– tripleee
Nov 19 '18 at 7:56
add a comment |
1
Even if portability is not an immediate concern, I see no benefit from using the nonportable longer Bash-only form.
– tripleee
Nov 19 '18 at 7:56
1
1
Even if portability is not an immediate concern, I see no benefit from using the nonportable longer Bash-only form.
– tripleee
Nov 19 '18 at 7:56
Even if portability is not an immediate concern, I see no benefit from using the nonportable longer Bash-only form.
– tripleee
Nov 19 '18 at 7:56
add a comment |
==
is a bash-specific alias for =
and it performs a string (lexical) comparison instead of a numeric comparison. eq
being a numeric comparison of course.
Finally, I usually prefer to use the form if [ "$a" == "$b" ]
8
Using==
here is bad form, as only=
is specified by POSIX.
– Charles Duffy
Oct 19 '15 at 5:45
5
If you really insist to use==
then put it in between[[
and]]
. (And make sure that the first line of your script specifies to use/bin/bash
.)
– holgero
Dec 21 '15 at 20:28
add a comment |
==
is a bash-specific alias for =
and it performs a string (lexical) comparison instead of a numeric comparison. eq
being a numeric comparison of course.
Finally, I usually prefer to use the form if [ "$a" == "$b" ]
8
Using==
here is bad form, as only=
is specified by POSIX.
– Charles Duffy
Oct 19 '15 at 5:45
5
If you really insist to use==
then put it in between[[
and]]
. (And make sure that the first line of your script specifies to use/bin/bash
.)
– holgero
Dec 21 '15 at 20:28
add a comment |
==
is a bash-specific alias for =
and it performs a string (lexical) comparison instead of a numeric comparison. eq
being a numeric comparison of course.
Finally, I usually prefer to use the form if [ "$a" == "$b" ]
==
is a bash-specific alias for =
and it performs a string (lexical) comparison instead of a numeric comparison. eq
being a numeric comparison of course.
Finally, I usually prefer to use the form if [ "$a" == "$b" ]
answered Dec 8 '13 at 3:33
Elliott FrischElliott Frisch
154k1391180
154k1391180
8
Using==
here is bad form, as only=
is specified by POSIX.
– Charles Duffy
Oct 19 '15 at 5:45
5
If you really insist to use==
then put it in between[[
and]]
. (And make sure that the first line of your script specifies to use/bin/bash
.)
– holgero
Dec 21 '15 at 20:28
add a comment |
8
Using==
here is bad form, as only=
is specified by POSIX.
– Charles Duffy
Oct 19 '15 at 5:45
5
If you really insist to use==
then put it in between[[
and]]
. (And make sure that the first line of your script specifies to use/bin/bash
.)
– holgero
Dec 21 '15 at 20:28
8
8
Using
==
here is bad form, as only =
is specified by POSIX.– Charles Duffy
Oct 19 '15 at 5:45
Using
==
here is bad form, as only =
is specified by POSIX.– Charles Duffy
Oct 19 '15 at 5:45
5
5
If you really insist to use
==
then put it in between [[
and ]]
. (And make sure that the first line of your script specifies to use /bin/bash
.)– holgero
Dec 21 '15 at 20:28
If you really insist to use
==
then put it in between [[
and ]]
. (And make sure that the first line of your script specifies to use /bin/bash
.)– holgero
Dec 21 '15 at 20:28
add a comment |
It depends on the Test Construct around the operator. Your options are double parenthesis, double braces, single braces, or test
If you use ((...)), you are testing arithmetic equity with ==
as in C:
$ (( 1==1 )); echo $?
0
$ (( 1==2 )); echo $?
1
(Note: 0
means true
in the Unix sense and non zero is a failed test)
Using -eq
inside of double parenthesis is a syntax error.
If you are using [...] (or single brace) or [[...]] (or double brace), or test
you can use one of -eq, -ne, -lt, -le, -gt, or -ge as an arithmetic comparison.
$ [ 1 -eq 1 ]; echo $?
0
$ [ 1 -eq 2 ]; echo $?
1
$ test 1 -eq 1; echo $?
0
The ==
inside of single or double braces (or test
command) is one of the string comparison operators:
$ [[ "abc" == "abc" ]]; echo $?
0
$ [[ "abc" == "ABC" ]]; echo $?
1
As a string operator, =
is equivalent to ==
and note the whitespace around =
or ==
its required.
While you can do [[ 1 == 1 ]]
or [[ $(( 1+1 )) == 2 ]]
it is testing the string equality -- not the arithmetic equality.
So -eq
produces the result probably expected that the integer value of 1+1
is equal to 2
even though the RH is a string and has a trailing space:
$ [[ $(( 1+1 )) -eq "2 " ]]; echo $?
0
While a string comparison of the same picks up the trailing space and therefor the string comparison fails:
$ [[ $(( 1+1 )) == "2 " ]]; echo $?
1
And a mistaken string comparison can produce the complete wrong answer. '10' is lexicographically less than '2', so a string comparison returns true
or 0
. So many are bitten by this bug:
$ [[ 10 < 2 ]]; echo $?
0
vs the correct test for 10 being arithmetically less than 2:
$ [[ 10 -lt 2 ]]; echo $?
1
In comments, there is a question of the technical reason using the integer -eq
on strings returns True for strings that are not the same:
$ [[ "yes" -eq "no" ]]; echo $?
0
The reason is that Bash is untyped. The -eq
causes the strings to be interpreted as integers if possible including base conversion:
$ [[ "0x10" -eq 16 ]]; echo $?
0
$ [[ "010" -eq 8 ]]; echo $?
0
$ [[ "100" -eq 100 ]]; echo $?
0
And 0
if Bash thinks it is just a string:
$ [[ "yes" -eq 0 ]]; echo $?
0
$ [[ "yes" -eq 1 ]]; echo $?
1
So [[ "yes" -eq "no" ]]
is equivalent to [[ 0 -eq 0 ]]
Last note: Many of the Bash specific extensions to the Test Constructs are not POSIX and therefore will fail in other shells. Other shells generally do not support [[...]]
and ((...))
or ==
.
I'm curious about the technical reason for[[ "yes" -eq "no" ]]
returning True. How does bash coerce these strings to integer values that can be compared? ;-)
– odony
May 11 '17 at 14:42
2
Bash variables are untyped so[[ "yes" -eq "no" ]]
is equivalent to[[ "yes" -eq 0 ]]
or[[ "yes" -eq "any_noninteger_string" ]]
-- All True. The-eq
forces integer comparison. The"yes"
is interpreted as a integer0
; the comparison is True if the other integer is either0
or the string result is0
.
– dawg
May 12 '17 at 19:55
@odony: See update
– dawg
May 13 '17 at 15:05
add a comment |
It depends on the Test Construct around the operator. Your options are double parenthesis, double braces, single braces, or test
If you use ((...)), you are testing arithmetic equity with ==
as in C:
$ (( 1==1 )); echo $?
0
$ (( 1==2 )); echo $?
1
(Note: 0
means true
in the Unix sense and non zero is a failed test)
Using -eq
inside of double parenthesis is a syntax error.
If you are using [...] (or single brace) or [[...]] (or double brace), or test
you can use one of -eq, -ne, -lt, -le, -gt, or -ge as an arithmetic comparison.
$ [ 1 -eq 1 ]; echo $?
0
$ [ 1 -eq 2 ]; echo $?
1
$ test 1 -eq 1; echo $?
0
The ==
inside of single or double braces (or test
command) is one of the string comparison operators:
$ [[ "abc" == "abc" ]]; echo $?
0
$ [[ "abc" == "ABC" ]]; echo $?
1
As a string operator, =
is equivalent to ==
and note the whitespace around =
or ==
its required.
While you can do [[ 1 == 1 ]]
or [[ $(( 1+1 )) == 2 ]]
it is testing the string equality -- not the arithmetic equality.
So -eq
produces the result probably expected that the integer value of 1+1
is equal to 2
even though the RH is a string and has a trailing space:
$ [[ $(( 1+1 )) -eq "2 " ]]; echo $?
0
While a string comparison of the same picks up the trailing space and therefor the string comparison fails:
$ [[ $(( 1+1 )) == "2 " ]]; echo $?
1
And a mistaken string comparison can produce the complete wrong answer. '10' is lexicographically less than '2', so a string comparison returns true
or 0
. So many are bitten by this bug:
$ [[ 10 < 2 ]]; echo $?
0
vs the correct test for 10 being arithmetically less than 2:
$ [[ 10 -lt 2 ]]; echo $?
1
In comments, there is a question of the technical reason using the integer -eq
on strings returns True for strings that are not the same:
$ [[ "yes" -eq "no" ]]; echo $?
0
The reason is that Bash is untyped. The -eq
causes the strings to be interpreted as integers if possible including base conversion:
$ [[ "0x10" -eq 16 ]]; echo $?
0
$ [[ "010" -eq 8 ]]; echo $?
0
$ [[ "100" -eq 100 ]]; echo $?
0
And 0
if Bash thinks it is just a string:
$ [[ "yes" -eq 0 ]]; echo $?
0
$ [[ "yes" -eq 1 ]]; echo $?
1
So [[ "yes" -eq "no" ]]
is equivalent to [[ 0 -eq 0 ]]
Last note: Many of the Bash specific extensions to the Test Constructs are not POSIX and therefore will fail in other shells. Other shells generally do not support [[...]]
and ((...))
or ==
.
I'm curious about the technical reason for[[ "yes" -eq "no" ]]
returning True. How does bash coerce these strings to integer values that can be compared? ;-)
– odony
May 11 '17 at 14:42
2
Bash variables are untyped so[[ "yes" -eq "no" ]]
is equivalent to[[ "yes" -eq 0 ]]
or[[ "yes" -eq "any_noninteger_string" ]]
-- All True. The-eq
forces integer comparison. The"yes"
is interpreted as a integer0
; the comparison is True if the other integer is either0
or the string result is0
.
– dawg
May 12 '17 at 19:55
@odony: See update
– dawg
May 13 '17 at 15:05
add a comment |
It depends on the Test Construct around the operator. Your options are double parenthesis, double braces, single braces, or test
If you use ((...)), you are testing arithmetic equity with ==
as in C:
$ (( 1==1 )); echo $?
0
$ (( 1==2 )); echo $?
1
(Note: 0
means true
in the Unix sense and non zero is a failed test)
Using -eq
inside of double parenthesis is a syntax error.
If you are using [...] (or single brace) or [[...]] (or double brace), or test
you can use one of -eq, -ne, -lt, -le, -gt, or -ge as an arithmetic comparison.
$ [ 1 -eq 1 ]; echo $?
0
$ [ 1 -eq 2 ]; echo $?
1
$ test 1 -eq 1; echo $?
0
The ==
inside of single or double braces (or test
command) is one of the string comparison operators:
$ [[ "abc" == "abc" ]]; echo $?
0
$ [[ "abc" == "ABC" ]]; echo $?
1
As a string operator, =
is equivalent to ==
and note the whitespace around =
or ==
its required.
While you can do [[ 1 == 1 ]]
or [[ $(( 1+1 )) == 2 ]]
it is testing the string equality -- not the arithmetic equality.
So -eq
produces the result probably expected that the integer value of 1+1
is equal to 2
even though the RH is a string and has a trailing space:
$ [[ $(( 1+1 )) -eq "2 " ]]; echo $?
0
While a string comparison of the same picks up the trailing space and therefor the string comparison fails:
$ [[ $(( 1+1 )) == "2 " ]]; echo $?
1
And a mistaken string comparison can produce the complete wrong answer. '10' is lexicographically less than '2', so a string comparison returns true
or 0
. So many are bitten by this bug:
$ [[ 10 < 2 ]]; echo $?
0
vs the correct test for 10 being arithmetically less than 2:
$ [[ 10 -lt 2 ]]; echo $?
1
In comments, there is a question of the technical reason using the integer -eq
on strings returns True for strings that are not the same:
$ [[ "yes" -eq "no" ]]; echo $?
0
The reason is that Bash is untyped. The -eq
causes the strings to be interpreted as integers if possible including base conversion:
$ [[ "0x10" -eq 16 ]]; echo $?
0
$ [[ "010" -eq 8 ]]; echo $?
0
$ [[ "100" -eq 100 ]]; echo $?
0
And 0
if Bash thinks it is just a string:
$ [[ "yes" -eq 0 ]]; echo $?
0
$ [[ "yes" -eq 1 ]]; echo $?
1
So [[ "yes" -eq "no" ]]
is equivalent to [[ 0 -eq 0 ]]
Last note: Many of the Bash specific extensions to the Test Constructs are not POSIX and therefore will fail in other shells. Other shells generally do not support [[...]]
and ((...))
or ==
.
It depends on the Test Construct around the operator. Your options are double parenthesis, double braces, single braces, or test
If you use ((...)), you are testing arithmetic equity with ==
as in C:
$ (( 1==1 )); echo $?
0
$ (( 1==2 )); echo $?
1
(Note: 0
means true
in the Unix sense and non zero is a failed test)
Using -eq
inside of double parenthesis is a syntax error.
If you are using [...] (or single brace) or [[...]] (or double brace), or test
you can use one of -eq, -ne, -lt, -le, -gt, or -ge as an arithmetic comparison.
$ [ 1 -eq 1 ]; echo $?
0
$ [ 1 -eq 2 ]; echo $?
1
$ test 1 -eq 1; echo $?
0
The ==
inside of single or double braces (or test
command) is one of the string comparison operators:
$ [[ "abc" == "abc" ]]; echo $?
0
$ [[ "abc" == "ABC" ]]; echo $?
1
As a string operator, =
is equivalent to ==
and note the whitespace around =
or ==
its required.
While you can do [[ 1 == 1 ]]
or [[ $(( 1+1 )) == 2 ]]
it is testing the string equality -- not the arithmetic equality.
So -eq
produces the result probably expected that the integer value of 1+1
is equal to 2
even though the RH is a string and has a trailing space:
$ [[ $(( 1+1 )) -eq "2 " ]]; echo $?
0
While a string comparison of the same picks up the trailing space and therefor the string comparison fails:
$ [[ $(( 1+1 )) == "2 " ]]; echo $?
1
And a mistaken string comparison can produce the complete wrong answer. '10' is lexicographically less than '2', so a string comparison returns true
or 0
. So many are bitten by this bug:
$ [[ 10 < 2 ]]; echo $?
0
vs the correct test for 10 being arithmetically less than 2:
$ [[ 10 -lt 2 ]]; echo $?
1
In comments, there is a question of the technical reason using the integer -eq
on strings returns True for strings that are not the same:
$ [[ "yes" -eq "no" ]]; echo $?
0
The reason is that Bash is untyped. The -eq
causes the strings to be interpreted as integers if possible including base conversion:
$ [[ "0x10" -eq 16 ]]; echo $?
0
$ [[ "010" -eq 8 ]]; echo $?
0
$ [[ "100" -eq 100 ]]; echo $?
0
And 0
if Bash thinks it is just a string:
$ [[ "yes" -eq 0 ]]; echo $?
0
$ [[ "yes" -eq 1 ]]; echo $?
1
So [[ "yes" -eq "no" ]]
is equivalent to [[ 0 -eq 0 ]]
Last note: Many of the Bash specific extensions to the Test Constructs are not POSIX and therefore will fail in other shells. Other shells generally do not support [[...]]
and ((...))
or ==
.
edited May 13 '17 at 4:31
answered Nov 4 '16 at 20:37
dawgdawg
58.8k1183152
58.8k1183152
I'm curious about the technical reason for[[ "yes" -eq "no" ]]
returning True. How does bash coerce these strings to integer values that can be compared? ;-)
– odony
May 11 '17 at 14:42
2
Bash variables are untyped so[[ "yes" -eq "no" ]]
is equivalent to[[ "yes" -eq 0 ]]
or[[ "yes" -eq "any_noninteger_string" ]]
-- All True. The-eq
forces integer comparison. The"yes"
is interpreted as a integer0
; the comparison is True if the other integer is either0
or the string result is0
.
– dawg
May 12 '17 at 19:55
@odony: See update
– dawg
May 13 '17 at 15:05
add a comment |
I'm curious about the technical reason for[[ "yes" -eq "no" ]]
returning True. How does bash coerce these strings to integer values that can be compared? ;-)
– odony
May 11 '17 at 14:42
2
Bash variables are untyped so[[ "yes" -eq "no" ]]
is equivalent to[[ "yes" -eq 0 ]]
or[[ "yes" -eq "any_noninteger_string" ]]
-- All True. The-eq
forces integer comparison. The"yes"
is interpreted as a integer0
; the comparison is True if the other integer is either0
or the string result is0
.
– dawg
May 12 '17 at 19:55
@odony: See update
– dawg
May 13 '17 at 15:05
I'm curious about the technical reason for
[[ "yes" -eq "no" ]]
returning True. How does bash coerce these strings to integer values that can be compared? ;-)– odony
May 11 '17 at 14:42
I'm curious about the technical reason for
[[ "yes" -eq "no" ]]
returning True. How does bash coerce these strings to integer values that can be compared? ;-)– odony
May 11 '17 at 14:42
2
2
Bash variables are untyped so
[[ "yes" -eq "no" ]]
is equivalent to [[ "yes" -eq 0 ]]
or [[ "yes" -eq "any_noninteger_string" ]]
-- All True. The -eq
forces integer comparison. The"yes"
is interpreted as a integer 0
; the comparison is True if the other integer is either 0
or the string result is 0
.– dawg
May 12 '17 at 19:55
Bash variables are untyped so
[[ "yes" -eq "no" ]]
is equivalent to [[ "yes" -eq 0 ]]
or [[ "yes" -eq "any_noninteger_string" ]]
-- All True. The -eq
forces integer comparison. The"yes"
is interpreted as a integer 0
; the comparison is True if the other integer is either 0
or the string result is 0
.– dawg
May 12 '17 at 19:55
@odony: See update
– dawg
May 13 '17 at 15:05
@odony: See update
– dawg
May 13 '17 at 15:05
add a comment |
Guys: Several answers show dangerous examples. OP's example [ $a == $b ]
specifically used unquoted variable substitution (as of Oct '17 edit). For [...]
that is safe for string equality.
But if you're going to enumerate alternatives like [[...]]
, you must inform also that the right-hand-side must be quoted. If not quoted, it is a pattern match! (From bash man page: "Any part of the pattern may be quoted to force it to be matched as a string.").
Here in bash, the two statements yielding "yes" are pattern matching, other three are string equality:
$ rht="A*"
$ lft="AB"
$ [ $lft = $rht ] && echo yes
$ [ $lft == $rht ] && echo yes
$ [[ $lft = $rht ]] && echo yes
yes
$ [[ $lft == $rht ]] && echo yes
yes
$ [[ $lft == "$rht" ]] && echo yes
$
That's a dangerous gotcha, thanks for posting it!
– joanis
Jan 16 at 21:24
add a comment |
Guys: Several answers show dangerous examples. OP's example [ $a == $b ]
specifically used unquoted variable substitution (as of Oct '17 edit). For [...]
that is safe for string equality.
But if you're going to enumerate alternatives like [[...]]
, you must inform also that the right-hand-side must be quoted. If not quoted, it is a pattern match! (From bash man page: "Any part of the pattern may be quoted to force it to be matched as a string.").
Here in bash, the two statements yielding "yes" are pattern matching, other three are string equality:
$ rht="A*"
$ lft="AB"
$ [ $lft = $rht ] && echo yes
$ [ $lft == $rht ] && echo yes
$ [[ $lft = $rht ]] && echo yes
yes
$ [[ $lft == $rht ]] && echo yes
yes
$ [[ $lft == "$rht" ]] && echo yes
$
That's a dangerous gotcha, thanks for posting it!
– joanis
Jan 16 at 21:24
add a comment |
Guys: Several answers show dangerous examples. OP's example [ $a == $b ]
specifically used unquoted variable substitution (as of Oct '17 edit). For [...]
that is safe for string equality.
But if you're going to enumerate alternatives like [[...]]
, you must inform also that the right-hand-side must be quoted. If not quoted, it is a pattern match! (From bash man page: "Any part of the pattern may be quoted to force it to be matched as a string.").
Here in bash, the two statements yielding "yes" are pattern matching, other three are string equality:
$ rht="A*"
$ lft="AB"
$ [ $lft = $rht ] && echo yes
$ [ $lft == $rht ] && echo yes
$ [[ $lft = $rht ]] && echo yes
yes
$ [[ $lft == $rht ]] && echo yes
yes
$ [[ $lft == "$rht" ]] && echo yes
$
Guys: Several answers show dangerous examples. OP's example [ $a == $b ]
specifically used unquoted variable substitution (as of Oct '17 edit). For [...]
that is safe for string equality.
But if you're going to enumerate alternatives like [[...]]
, you must inform also that the right-hand-side must be quoted. If not quoted, it is a pattern match! (From bash man page: "Any part of the pattern may be quoted to force it to be matched as a string.").
Here in bash, the two statements yielding "yes" are pattern matching, other three are string equality:
$ rht="A*"
$ lft="AB"
$ [ $lft = $rht ] && echo yes
$ [ $lft == $rht ] && echo yes
$ [[ $lft = $rht ]] && echo yes
yes
$ [[ $lft == $rht ]] && echo yes
yes
$ [[ $lft == "$rht" ]] && echo yes
$
answered Jan 15 '18 at 3:02
bk-sebk-se
19526
19526
That's a dangerous gotcha, thanks for posting it!
– joanis
Jan 16 at 21:24
add a comment |
That's a dangerous gotcha, thanks for posting it!
– joanis
Jan 16 at 21:24
That's a dangerous gotcha, thanks for posting it!
– joanis
Jan 16 at 21:24
That's a dangerous gotcha, thanks for posting it!
– joanis
Jan 16 at 21:24
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f20449543%2fbash-equality-operators-eq%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown