Difference between [[ expr1 || expr2 ]] and [[ expr1 ]] || [[ expr2 ]]Difference between >> and >> operators?What's the difference between `` and $()?What's the difference between “==” and “=~”?What's the difference between $@ and $*Difference between / and //Difference between 1> and >Difference between `/` and `//` directoriesdifference between ~ and cdwhat are the differences between `==` and `=` in conditional expressions?Whats the difference between $_ and !$?
Multi tool use
Players of unusual orchestral instruments
Is this floating-point optimization allowed?
Are there J.S. Bach pieces that do not start with the tonic chord?
Was the Ford Model T black because of the speed black paint dries?
Back to the nineties!
How does one stock fund's charge of 1% more in operating expenses than another fund lower expected returns by 10%?
Installing ubuntu with HD + SSD
Military Weapon System
Why hasn't the U.S. government paid war reparations to any country it attacked?
What happens if you cast Dissonant Whispers on a Hydra?
nginx serves wrong domain site. It doenst shows default site if no configuration applies
What does "Fotze" really mean?
Report how much space is used and available in storage in ZFS on FreeBSD
Metric version of "footage"?
To accent or not to accent in Greek
How to determine port and starboard on a rotating wheel space station?
How can an advanced civilization forget how to manufacture its technology?
Was adding milk to tea started to reduce employee tea break time?
Is Arc Length always irrational between two rational points?
Why did the Japanese attack the Aleutians at the same time as Midway?
Filtering fine silt/mud from water (not necessarily bacteria etc.)
Is `curl something | sudo bash -` a reasonably safe installation method?
Mistakenly modified `/bin/sh'
How to check the quality of an audio sample?
Difference between [[ expr1 || expr2 ]] and [[ expr1 ]] || [[ expr2 ]]
Difference between >> and >> operators?What's the difference between `` and $()?What's the difference between “==” and “=~”?What's the difference between $@ and $*Difference between / and //Difference between 1> and >Difference between `/` and `//` directoriesdifference between ~ and cdwhat are the differences between `==` and `=` in conditional expressions?Whats the difference between $_ and !$?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
Consider two conditional expressions expr1
and expr2
, for example $i -eq $j
and $k -eq $l
. We can write this in bash
a number of ways. Here are two possibilities
[[ expr1 || expr2 ]]
[[ expr1 ]] || [[ expr2 ]]
I'm fairly sure I've seen recommendations here that the second should be preferred, but I can't find evidence to support this.
Here is a sample script that seems to demonstrate there is no difference:
for i in 0 1
do
for j in 0 1
do
for k in 0 1
do
for l in 0 1
do
if [[ $i -eq $j || $k -eq $l ]]; then printf "1-yest"; else printf "1-not"; fi
if [[ $i -eq $j ]] || [[ $k -eq $l ]]; then printf "2-yesn"; else printf "2-non"; fi
done
done
done
done
and output showing that both condition constructs produce the same result:
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-no 2-no
1-no 2-no
1-yes 2-yes
1-yes 2-yes
1-no 2-no
1-no 2-no
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
Is there any benefit to using one construct over the other?
For bonus points, same question but generalising to multiple conditions using ||
and &&
. For example, [[ expr1 && expr2 || expr3 ]]
.
bash
add a comment |
Consider two conditional expressions expr1
and expr2
, for example $i -eq $j
and $k -eq $l
. We can write this in bash
a number of ways. Here are two possibilities
[[ expr1 || expr2 ]]
[[ expr1 ]] || [[ expr2 ]]
I'm fairly sure I've seen recommendations here that the second should be preferred, but I can't find evidence to support this.
Here is a sample script that seems to demonstrate there is no difference:
for i in 0 1
do
for j in 0 1
do
for k in 0 1
do
for l in 0 1
do
if [[ $i -eq $j || $k -eq $l ]]; then printf "1-yest"; else printf "1-not"; fi
if [[ $i -eq $j ]] || [[ $k -eq $l ]]; then printf "2-yesn"; else printf "2-non"; fi
done
done
done
done
and output showing that both condition constructs produce the same result:
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-no 2-no
1-no 2-no
1-yes 2-yes
1-yes 2-yes
1-no 2-no
1-no 2-no
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
Is there any benefit to using one construct over the other?
For bonus points, same question but generalising to multiple conditions using ||
and &&
. For example, [[ expr1 && expr2 || expr3 ]]
.
bash
With respect to why recommendations of this type are often given wrt.[
ortest
(not[[
), search for theOB
tags (linked to the "obsolescent" definition) in the POSIX spec fortest
. Intest
, there are some pathological cases where it can be impossible to tell if(
or)
is meant to be syntax meaningful to the test command or a string to be tested, so people who ignore the obsolescence markers and use that syntax can actually need the otherwise-obsolete"x$foo"
practice; with[[
, that isn't a problem.
– Charles Duffy
Jul 5 at 22:07
add a comment |
Consider two conditional expressions expr1
and expr2
, for example $i -eq $j
and $k -eq $l
. We can write this in bash
a number of ways. Here are two possibilities
[[ expr1 || expr2 ]]
[[ expr1 ]] || [[ expr2 ]]
I'm fairly sure I've seen recommendations here that the second should be preferred, but I can't find evidence to support this.
Here is a sample script that seems to demonstrate there is no difference:
for i in 0 1
do
for j in 0 1
do
for k in 0 1
do
for l in 0 1
do
if [[ $i -eq $j || $k -eq $l ]]; then printf "1-yest"; else printf "1-not"; fi
if [[ $i -eq $j ]] || [[ $k -eq $l ]]; then printf "2-yesn"; else printf "2-non"; fi
done
done
done
done
and output showing that both condition constructs produce the same result:
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-no 2-no
1-no 2-no
1-yes 2-yes
1-yes 2-yes
1-no 2-no
1-no 2-no
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
Is there any benefit to using one construct over the other?
For bonus points, same question but generalising to multiple conditions using ||
and &&
. For example, [[ expr1 && expr2 || expr3 ]]
.
bash
Consider two conditional expressions expr1
and expr2
, for example $i -eq $j
and $k -eq $l
. We can write this in bash
a number of ways. Here are two possibilities
[[ expr1 || expr2 ]]
[[ expr1 ]] || [[ expr2 ]]
I'm fairly sure I've seen recommendations here that the second should be preferred, but I can't find evidence to support this.
Here is a sample script that seems to demonstrate there is no difference:
for i in 0 1
do
for j in 0 1
do
for k in 0 1
do
for l in 0 1
do
if [[ $i -eq $j || $k -eq $l ]]; then printf "1-yest"; else printf "1-not"; fi
if [[ $i -eq $j ]] || [[ $k -eq $l ]]; then printf "2-yesn"; else printf "2-non"; fi
done
done
done
done
and output showing that both condition constructs produce the same result:
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-no 2-no
1-no 2-no
1-yes 2-yes
1-yes 2-yes
1-no 2-no
1-no 2-no
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
Is there any benefit to using one construct over the other?
For bonus points, same question but generalising to multiple conditions using ||
and &&
. For example, [[ expr1 && expr2 || expr3 ]]
.
bash
bash
asked Jul 5 at 10:02
roaimaroaima
48.2k7 gold badges63 silver badges131 bronze badges
48.2k7 gold badges63 silver badges131 bronze badges
With respect to why recommendations of this type are often given wrt.[
ortest
(not[[
), search for theOB
tags (linked to the "obsolescent" definition) in the POSIX spec fortest
. Intest
, there are some pathological cases where it can be impossible to tell if(
or)
is meant to be syntax meaningful to the test command or a string to be tested, so people who ignore the obsolescence markers and use that syntax can actually need the otherwise-obsolete"x$foo"
practice; with[[
, that isn't a problem.
– Charles Duffy
Jul 5 at 22:07
add a comment |
With respect to why recommendations of this type are often given wrt.[
ortest
(not[[
), search for theOB
tags (linked to the "obsolescent" definition) in the POSIX spec fortest
. Intest
, there are some pathological cases where it can be impossible to tell if(
or)
is meant to be syntax meaningful to the test command or a string to be tested, so people who ignore the obsolescence markers and use that syntax can actually need the otherwise-obsolete"x$foo"
practice; with[[
, that isn't a problem.
– Charles Duffy
Jul 5 at 22:07
With respect to why recommendations of this type are often given wrt.
[
or test
(not [[
), search for the OB
tags (linked to the "obsolescent" definition) in the POSIX spec for test
. In test
, there are some pathological cases where it can be impossible to tell if (
or )
is meant to be syntax meaningful to the test command or a string to be tested, so people who ignore the obsolescence markers and use that syntax can actually need the otherwise-obsolete "x$foo"
practice; with [[
, that isn't a problem.– Charles Duffy
Jul 5 at 22:07
With respect to why recommendations of this type are often given wrt.
[
or test
(not [[
), search for the OB
tags (linked to the "obsolescent" definition) in the POSIX spec for test
. In test
, there are some pathological cases where it can be impossible to tell if (
or )
is meant to be syntax meaningful to the test command or a string to be tested, so people who ignore the obsolescence markers and use that syntax can actually need the otherwise-obsolete "x$foo"
practice; with [[
, that isn't a problem.– Charles Duffy
Jul 5 at 22:07
add a comment |
1 Answer
1
active
oldest
votes
I think the recommendation you saw was for POSIX sh and/or the test
command which doubles as the [
command, rather than the [[
construct which appeared in ksh (thanks Stéphane Chazelas for the tip) and is also used for example in bash, zsh and some other shells.
In most languages, like C, when a clause is already known to be true or false, there's no need to evaluate the remainder parts depending on the operation: if true not after a logical or following it, if false not after a logical and, etc. This of course allows for example to stop when a pointer is NULL and not try to dereference it in the next clause.
But sh's [ expr1 -o expr2 ]
construct (including bash's implementation) doesn't do this: it always evaluates both sides, when one would want only expr1 to be evaluated. This might have been done for compatibility with the test
command implementation. On the other hand, sh's ||
and &&
do follow the usual principle: not evaluated if it won't change the result.
So the difference to note would be:
: > /tmp/effect #clear effect
if [ 1 -eq 1 -o $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]; then
echo true;
fi
cat /tmp/effect
which yields:
true
or-was-evaluated
Above, each [
could have been replaced with /usr/bin/[
which is an alias to the test
command, used before [
was made built-in to shells.
While the two next constructs:
: > /tmp/effect #clear effect
if [ 1 -eq 1 ] || [ $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]; then
echo true;
fi
cat /tmp/effect
or
: > /tmp/effect #clear effect
if [[ 1 -eq 1 || $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]]; then
echo true;
fi
cat /tmp/effect
Will only yield true
and leave effect
empty: ||
behaves correctly, and [[
corrected this issue too.
UPDATE:
As @StéphaneChazelas commented, I missed several differences related to the initial question. I'll just put here the most important one (at least to me): priority of operators.
While the shell will not considere precedence:
if true || true && false; then
echo true
else
echo false
fi
yields (because there is no precedence and thus first true || true
is evaluated, and then && false
):
false
inside [[ ]]
the &&
operator has precedence over ||
:
if [[ 1 -eq 1 || 1 -eq 1 && 1 -eq 0 ]]; then
echo true
else
echo false
fi
yields (because 1 -eq 1 && 1 -eq 0
is grouped and is thus the 2nd member of ||
):
true
at least for ksh, bash, zsh.
So [[ ]]
has improved behaviour over both [ ]
and direct shell logical operators.
1
[ x -o y ]
doesn't have to evaluate both side. While GNUtest
or the[
builtin ofbash
do, you'd find withstrace zsh -c '[ x -o -f /x ]'
that[
doesn't try to stat()/x
. Same withmksh
. But it's true that-o
and-a
are severely broken, can't be used reliably and are deprecated by POSIX.
– Stéphane Chazelas
Jul 5 at 11:20
1
One difference is that inside[[...]]
,&&
has higher precedence than||
, while outside they have equal precedence. Compareksh -c '[[ x || x && "" ]]'
vssh -c 'true || true && false'
– Stéphane Chazelas
Jul 5 at 11:24
1
Note that the standard[
/test
utility doesn't have a==
operator. The equality operator is=
(note that inside ksh's[[...]]
,=
/==
are not equality operators, but pattern matching ones).
– Stéphane Chazelas
Jul 5 at 11:26
1
It's the other way round.&&
has precedence over||
inside[[...]]
(or((...))
) but not the&&
and||
shell operators.[[ x || y && z ]]
isx || (y && z)
whilex || y && z
is(x || y) && z
(operators evaluated left to right without precedence). Similar to how*
has precedence over+
(1 + 2 * 3
is1 + (2 * 3)
) but+
and-
have same precedence.
– Stéphane Chazelas
Jul 5 at 13:04
1
If&&
has precedence over||
, then it should betrue || (true && false)
, instead of(true || true) && false
– Prvt_Yadv
Jul 5 at 13:11
|
show 4 more comments
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
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: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
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%2funix.stackexchange.com%2fquestions%2f528505%2fdifference-between-expr1-expr2-and-expr1-expr2%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
I think the recommendation you saw was for POSIX sh and/or the test
command which doubles as the [
command, rather than the [[
construct which appeared in ksh (thanks Stéphane Chazelas for the tip) and is also used for example in bash, zsh and some other shells.
In most languages, like C, when a clause is already known to be true or false, there's no need to evaluate the remainder parts depending on the operation: if true not after a logical or following it, if false not after a logical and, etc. This of course allows for example to stop when a pointer is NULL and not try to dereference it in the next clause.
But sh's [ expr1 -o expr2 ]
construct (including bash's implementation) doesn't do this: it always evaluates both sides, when one would want only expr1 to be evaluated. This might have been done for compatibility with the test
command implementation. On the other hand, sh's ||
and &&
do follow the usual principle: not evaluated if it won't change the result.
So the difference to note would be:
: > /tmp/effect #clear effect
if [ 1 -eq 1 -o $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]; then
echo true;
fi
cat /tmp/effect
which yields:
true
or-was-evaluated
Above, each [
could have been replaced with /usr/bin/[
which is an alias to the test
command, used before [
was made built-in to shells.
While the two next constructs:
: > /tmp/effect #clear effect
if [ 1 -eq 1 ] || [ $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]; then
echo true;
fi
cat /tmp/effect
or
: > /tmp/effect #clear effect
if [[ 1 -eq 1 || $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]]; then
echo true;
fi
cat /tmp/effect
Will only yield true
and leave effect
empty: ||
behaves correctly, and [[
corrected this issue too.
UPDATE:
As @StéphaneChazelas commented, I missed several differences related to the initial question. I'll just put here the most important one (at least to me): priority of operators.
While the shell will not considere precedence:
if true || true && false; then
echo true
else
echo false
fi
yields (because there is no precedence and thus first true || true
is evaluated, and then && false
):
false
inside [[ ]]
the &&
operator has precedence over ||
:
if [[ 1 -eq 1 || 1 -eq 1 && 1 -eq 0 ]]; then
echo true
else
echo false
fi
yields (because 1 -eq 1 && 1 -eq 0
is grouped and is thus the 2nd member of ||
):
true
at least for ksh, bash, zsh.
So [[ ]]
has improved behaviour over both [ ]
and direct shell logical operators.
1
[ x -o y ]
doesn't have to evaluate both side. While GNUtest
or the[
builtin ofbash
do, you'd find withstrace zsh -c '[ x -o -f /x ]'
that[
doesn't try to stat()/x
. Same withmksh
. But it's true that-o
and-a
are severely broken, can't be used reliably and are deprecated by POSIX.
– Stéphane Chazelas
Jul 5 at 11:20
1
One difference is that inside[[...]]
,&&
has higher precedence than||
, while outside they have equal precedence. Compareksh -c '[[ x || x && "" ]]'
vssh -c 'true || true && false'
– Stéphane Chazelas
Jul 5 at 11:24
1
Note that the standard[
/test
utility doesn't have a==
operator. The equality operator is=
(note that inside ksh's[[...]]
,=
/==
are not equality operators, but pattern matching ones).
– Stéphane Chazelas
Jul 5 at 11:26
1
It's the other way round.&&
has precedence over||
inside[[...]]
(or((...))
) but not the&&
and||
shell operators.[[ x || y && z ]]
isx || (y && z)
whilex || y && z
is(x || y) && z
(operators evaluated left to right without precedence). Similar to how*
has precedence over+
(1 + 2 * 3
is1 + (2 * 3)
) but+
and-
have same precedence.
– Stéphane Chazelas
Jul 5 at 13:04
1
If&&
has precedence over||
, then it should betrue || (true && false)
, instead of(true || true) && false
– Prvt_Yadv
Jul 5 at 13:11
|
show 4 more comments
I think the recommendation you saw was for POSIX sh and/or the test
command which doubles as the [
command, rather than the [[
construct which appeared in ksh (thanks Stéphane Chazelas for the tip) and is also used for example in bash, zsh and some other shells.
In most languages, like C, when a clause is already known to be true or false, there's no need to evaluate the remainder parts depending on the operation: if true not after a logical or following it, if false not after a logical and, etc. This of course allows for example to stop when a pointer is NULL and not try to dereference it in the next clause.
But sh's [ expr1 -o expr2 ]
construct (including bash's implementation) doesn't do this: it always evaluates both sides, when one would want only expr1 to be evaluated. This might have been done for compatibility with the test
command implementation. On the other hand, sh's ||
and &&
do follow the usual principle: not evaluated if it won't change the result.
So the difference to note would be:
: > /tmp/effect #clear effect
if [ 1 -eq 1 -o $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]; then
echo true;
fi
cat /tmp/effect
which yields:
true
or-was-evaluated
Above, each [
could have been replaced with /usr/bin/[
which is an alias to the test
command, used before [
was made built-in to shells.
While the two next constructs:
: > /tmp/effect #clear effect
if [ 1 -eq 1 ] || [ $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]; then
echo true;
fi
cat /tmp/effect
or
: > /tmp/effect #clear effect
if [[ 1 -eq 1 || $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]]; then
echo true;
fi
cat /tmp/effect
Will only yield true
and leave effect
empty: ||
behaves correctly, and [[
corrected this issue too.
UPDATE:
As @StéphaneChazelas commented, I missed several differences related to the initial question. I'll just put here the most important one (at least to me): priority of operators.
While the shell will not considere precedence:
if true || true && false; then
echo true
else
echo false
fi
yields (because there is no precedence and thus first true || true
is evaluated, and then && false
):
false
inside [[ ]]
the &&
operator has precedence over ||
:
if [[ 1 -eq 1 || 1 -eq 1 && 1 -eq 0 ]]; then
echo true
else
echo false
fi
yields (because 1 -eq 1 && 1 -eq 0
is grouped and is thus the 2nd member of ||
):
true
at least for ksh, bash, zsh.
So [[ ]]
has improved behaviour over both [ ]
and direct shell logical operators.
1
[ x -o y ]
doesn't have to evaluate both side. While GNUtest
or the[
builtin ofbash
do, you'd find withstrace zsh -c '[ x -o -f /x ]'
that[
doesn't try to stat()/x
. Same withmksh
. But it's true that-o
and-a
are severely broken, can't be used reliably and are deprecated by POSIX.
– Stéphane Chazelas
Jul 5 at 11:20
1
One difference is that inside[[...]]
,&&
has higher precedence than||
, while outside they have equal precedence. Compareksh -c '[[ x || x && "" ]]'
vssh -c 'true || true && false'
– Stéphane Chazelas
Jul 5 at 11:24
1
Note that the standard[
/test
utility doesn't have a==
operator. The equality operator is=
(note that inside ksh's[[...]]
,=
/==
are not equality operators, but pattern matching ones).
– Stéphane Chazelas
Jul 5 at 11:26
1
It's the other way round.&&
has precedence over||
inside[[...]]
(or((...))
) but not the&&
and||
shell operators.[[ x || y && z ]]
isx || (y && z)
whilex || y && z
is(x || y) && z
(operators evaluated left to right without precedence). Similar to how*
has precedence over+
(1 + 2 * 3
is1 + (2 * 3)
) but+
and-
have same precedence.
– Stéphane Chazelas
Jul 5 at 13:04
1
If&&
has precedence over||
, then it should betrue || (true && false)
, instead of(true || true) && false
– Prvt_Yadv
Jul 5 at 13:11
|
show 4 more comments
I think the recommendation you saw was for POSIX sh and/or the test
command which doubles as the [
command, rather than the [[
construct which appeared in ksh (thanks Stéphane Chazelas for the tip) and is also used for example in bash, zsh and some other shells.
In most languages, like C, when a clause is already known to be true or false, there's no need to evaluate the remainder parts depending on the operation: if true not after a logical or following it, if false not after a logical and, etc. This of course allows for example to stop when a pointer is NULL and not try to dereference it in the next clause.
But sh's [ expr1 -o expr2 ]
construct (including bash's implementation) doesn't do this: it always evaluates both sides, when one would want only expr1 to be evaluated. This might have been done for compatibility with the test
command implementation. On the other hand, sh's ||
and &&
do follow the usual principle: not evaluated if it won't change the result.
So the difference to note would be:
: > /tmp/effect #clear effect
if [ 1 -eq 1 -o $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]; then
echo true;
fi
cat /tmp/effect
which yields:
true
or-was-evaluated
Above, each [
could have been replaced with /usr/bin/[
which is an alias to the test
command, used before [
was made built-in to shells.
While the two next constructs:
: > /tmp/effect #clear effect
if [ 1 -eq 1 ] || [ $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]; then
echo true;
fi
cat /tmp/effect
or
: > /tmp/effect #clear effect
if [[ 1 -eq 1 || $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]]; then
echo true;
fi
cat /tmp/effect
Will only yield true
and leave effect
empty: ||
behaves correctly, and [[
corrected this issue too.
UPDATE:
As @StéphaneChazelas commented, I missed several differences related to the initial question. I'll just put here the most important one (at least to me): priority of operators.
While the shell will not considere precedence:
if true || true && false; then
echo true
else
echo false
fi
yields (because there is no precedence and thus first true || true
is evaluated, and then && false
):
false
inside [[ ]]
the &&
operator has precedence over ||
:
if [[ 1 -eq 1 || 1 -eq 1 && 1 -eq 0 ]]; then
echo true
else
echo false
fi
yields (because 1 -eq 1 && 1 -eq 0
is grouped and is thus the 2nd member of ||
):
true
at least for ksh, bash, zsh.
So [[ ]]
has improved behaviour over both [ ]
and direct shell logical operators.
I think the recommendation you saw was for POSIX sh and/or the test
command which doubles as the [
command, rather than the [[
construct which appeared in ksh (thanks Stéphane Chazelas for the tip) and is also used for example in bash, zsh and some other shells.
In most languages, like C, when a clause is already known to be true or false, there's no need to evaluate the remainder parts depending on the operation: if true not after a logical or following it, if false not after a logical and, etc. This of course allows for example to stop when a pointer is NULL and not try to dereference it in the next clause.
But sh's [ expr1 -o expr2 ]
construct (including bash's implementation) doesn't do this: it always evaluates both sides, when one would want only expr1 to be evaluated. This might have been done for compatibility with the test
command implementation. On the other hand, sh's ||
and &&
do follow the usual principle: not evaluated if it won't change the result.
So the difference to note would be:
: > /tmp/effect #clear effect
if [ 1 -eq 1 -o $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]; then
echo true;
fi
cat /tmp/effect
which yields:
true
or-was-evaluated
Above, each [
could have been replaced with /usr/bin/[
which is an alias to the test
command, used before [
was made built-in to shells.
While the two next constructs:
: > /tmp/effect #clear effect
if [ 1 -eq 1 ] || [ $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]; then
echo true;
fi
cat /tmp/effect
or
: > /tmp/effect #clear effect
if [[ 1 -eq 1 || $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]]; then
echo true;
fi
cat /tmp/effect
Will only yield true
and leave effect
empty: ||
behaves correctly, and [[
corrected this issue too.
UPDATE:
As @StéphaneChazelas commented, I missed several differences related to the initial question. I'll just put here the most important one (at least to me): priority of operators.
While the shell will not considere precedence:
if true || true && false; then
echo true
else
echo false
fi
yields (because there is no precedence and thus first true || true
is evaluated, and then && false
):
false
inside [[ ]]
the &&
operator has precedence over ||
:
if [[ 1 -eq 1 || 1 -eq 1 && 1 -eq 0 ]]; then
echo true
else
echo false
fi
yields (because 1 -eq 1 && 1 -eq 0
is grouped and is thus the 2nd member of ||
):
true
at least for ksh, bash, zsh.
So [[ ]]
has improved behaviour over both [ ]
and direct shell logical operators.
edited Jul 5 at 14:56
answered Jul 5 at 11:12
A.BA.B
7,8401 gold badge14 silver badges36 bronze badges
7,8401 gold badge14 silver badges36 bronze badges
1
[ x -o y ]
doesn't have to evaluate both side. While GNUtest
or the[
builtin ofbash
do, you'd find withstrace zsh -c '[ x -o -f /x ]'
that[
doesn't try to stat()/x
. Same withmksh
. But it's true that-o
and-a
are severely broken, can't be used reliably and are deprecated by POSIX.
– Stéphane Chazelas
Jul 5 at 11:20
1
One difference is that inside[[...]]
,&&
has higher precedence than||
, while outside they have equal precedence. Compareksh -c '[[ x || x && "" ]]'
vssh -c 'true || true && false'
– Stéphane Chazelas
Jul 5 at 11:24
1
Note that the standard[
/test
utility doesn't have a==
operator. The equality operator is=
(note that inside ksh's[[...]]
,=
/==
are not equality operators, but pattern matching ones).
– Stéphane Chazelas
Jul 5 at 11:26
1
It's the other way round.&&
has precedence over||
inside[[...]]
(or((...))
) but not the&&
and||
shell operators.[[ x || y && z ]]
isx || (y && z)
whilex || y && z
is(x || y) && z
(operators evaluated left to right without precedence). Similar to how*
has precedence over+
(1 + 2 * 3
is1 + (2 * 3)
) but+
and-
have same precedence.
– Stéphane Chazelas
Jul 5 at 13:04
1
If&&
has precedence over||
, then it should betrue || (true && false)
, instead of(true || true) && false
– Prvt_Yadv
Jul 5 at 13:11
|
show 4 more comments
1
[ x -o y ]
doesn't have to evaluate both side. While GNUtest
or the[
builtin ofbash
do, you'd find withstrace zsh -c '[ x -o -f /x ]'
that[
doesn't try to stat()/x
. Same withmksh
. But it's true that-o
and-a
are severely broken, can't be used reliably and are deprecated by POSIX.
– Stéphane Chazelas
Jul 5 at 11:20
1
One difference is that inside[[...]]
,&&
has higher precedence than||
, while outside they have equal precedence. Compareksh -c '[[ x || x && "" ]]'
vssh -c 'true || true && false'
– Stéphane Chazelas
Jul 5 at 11:24
1
Note that the standard[
/test
utility doesn't have a==
operator. The equality operator is=
(note that inside ksh's[[...]]
,=
/==
are not equality operators, but pattern matching ones).
– Stéphane Chazelas
Jul 5 at 11:26
1
It's the other way round.&&
has precedence over||
inside[[...]]
(or((...))
) but not the&&
and||
shell operators.[[ x || y && z ]]
isx || (y && z)
whilex || y && z
is(x || y) && z
(operators evaluated left to right without precedence). Similar to how*
has precedence over+
(1 + 2 * 3
is1 + (2 * 3)
) but+
and-
have same precedence.
– Stéphane Chazelas
Jul 5 at 13:04
1
If&&
has precedence over||
, then it should betrue || (true && false)
, instead of(true || true) && false
– Prvt_Yadv
Jul 5 at 13:11
1
1
[ x -o y ]
doesn't have to evaluate both side. While GNU test
or the [
builtin of bash
do, you'd find with strace zsh -c '[ x -o -f /x ]'
that [
doesn't try to stat() /x
. Same with mksh
. But it's true that -o
and -a
are severely broken, can't be used reliably and are deprecated by POSIX.– Stéphane Chazelas
Jul 5 at 11:20
[ x -o y ]
doesn't have to evaluate both side. While GNU test
or the [
builtin of bash
do, you'd find with strace zsh -c '[ x -o -f /x ]'
that [
doesn't try to stat() /x
. Same with mksh
. But it's true that -o
and -a
are severely broken, can't be used reliably and are deprecated by POSIX.– Stéphane Chazelas
Jul 5 at 11:20
1
1
One difference is that inside
[[...]]
, &&
has higher precedence than ||
, while outside they have equal precedence. Compare ksh -c '[[ x || x && "" ]]'
vs sh -c 'true || true && false'
– Stéphane Chazelas
Jul 5 at 11:24
One difference is that inside
[[...]]
, &&
has higher precedence than ||
, while outside they have equal precedence. Compare ksh -c '[[ x || x && "" ]]'
vs sh -c 'true || true && false'
– Stéphane Chazelas
Jul 5 at 11:24
1
1
Note that the standard
[
/ test
utility doesn't have a ==
operator. The equality operator is =
(note that inside ksh's [[...]]
, =
/==
are not equality operators, but pattern matching ones).– Stéphane Chazelas
Jul 5 at 11:26
Note that the standard
[
/ test
utility doesn't have a ==
operator. The equality operator is =
(note that inside ksh's [[...]]
, =
/==
are not equality operators, but pattern matching ones).– Stéphane Chazelas
Jul 5 at 11:26
1
1
It's the other way round.
&&
has precedence over ||
inside [[...]]
(or ((...))
) but not the &&
and ||
shell operators. [[ x || y && z ]]
is x || (y && z)
while x || y && z
is (x || y) && z
(operators evaluated left to right without precedence). Similar to how *
has precedence over +
(1 + 2 * 3
is 1 + (2 * 3)
) but +
and -
have same precedence.– Stéphane Chazelas
Jul 5 at 13:04
It's the other way round.
&&
has precedence over ||
inside [[...]]
(or ((...))
) but not the &&
and ||
shell operators. [[ x || y && z ]]
is x || (y && z)
while x || y && z
is (x || y) && z
(operators evaluated left to right without precedence). Similar to how *
has precedence over +
(1 + 2 * 3
is 1 + (2 * 3)
) but +
and -
have same precedence.– Stéphane Chazelas
Jul 5 at 13:04
1
1
If
&&
has precedence over ||
, then it should be true || (true && false)
, instead of (true || true) && false
– Prvt_Yadv
Jul 5 at 13:11
If
&&
has precedence over ||
, then it should be true || (true && false)
, instead of (true || true) && false
– Prvt_Yadv
Jul 5 at 13:11
|
show 4 more comments
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- 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%2funix.stackexchange.com%2fquestions%2f528505%2fdifference-between-expr1-expr2-and-expr1-expr2%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
zM Nq89TrkKG YbPY96wo5D,OkJVx8N t8F,nN3eE8xtnRRuBqiOxUQ9I,TBlw0TLuAM2Lg2f TLy1I1MIxNi4bH BztWi1pfwiC,lbp
With respect to why recommendations of this type are often given wrt.
[
ortest
(not[[
), search for theOB
tags (linked to the "obsolescent" definition) in the POSIX spec fortest
. Intest
, there are some pathological cases where it can be impossible to tell if(
or)
is meant to be syntax meaningful to the test command or a string to be tested, so people who ignore the obsolescence markers and use that syntax can actually need the otherwise-obsolete"x$foo"
practice; with[[
, that isn't a problem.– Charles Duffy
Jul 5 at 22:07