Precedence of the shell logical operators &&, ||












111















I am trying to understand how the logical operator precedence works in bash. For example, I would have expected, that the following command does not echo anything.



true || echo aaa && echo bbb


However, contrary to my expectation, bbb gets printed.



Can somebody please explain, how can I make sense of compounded && and || operators in bash?










share|improve this question





























    111















    I am trying to understand how the logical operator precedence works in bash. For example, I would have expected, that the following command does not echo anything.



    true || echo aaa && echo bbb


    However, contrary to my expectation, bbb gets printed.



    Can somebody please explain, how can I make sense of compounded && and || operators in bash?










    share|improve this question



























      111












      111








      111


      46






      I am trying to understand how the logical operator precedence works in bash. For example, I would have expected, that the following command does not echo anything.



      true || echo aaa && echo bbb


      However, contrary to my expectation, bbb gets printed.



      Can somebody please explain, how can I make sense of compounded && and || operators in bash?










      share|improve this question
















      I am trying to understand how the logical operator precedence works in bash. For example, I would have expected, that the following command does not echo anything.



      true || echo aaa && echo bbb


      However, contrary to my expectation, bbb gets printed.



      Can somebody please explain, how can I make sense of compounded && and || operators in bash?







      bash shell precedence






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 43 mins ago









      codeforester

      376317




      376317










      asked Aug 30 '13 at 11:16









      Martin VegterMartin Vegter

      28437126241




      28437126241






















          4 Answers
          4






          active

          oldest

          votes


















          110














          In many computer languages, operators with the same precedence are left-associative. That is, in the absence of grouping structures, leftmost operations are executed first. Bash is no exception to this rule.



          This is important because, in Bash, && and || have the same precedence.



          So what happens in your example is that the leftmost operation (||) is carried out first:



          true || echo aaa


          Since true is obviously true, the || operator short-circuits and the whole statement is considered true without the need to evaluate echo aaa as you would expect. Now it remains to do the rightmost operation:



          (...) && echo bbb


          Since the first operation evaluated to true (i.e. had a 0 exit status), it's as if you're executing



          true && echo bbb


          so the && will not short-circuit, which is why you see bbb echoed.



          You would get the same behavior with



          false && echo aaa || echo bbb


          Notes based on the comments




          • You should note that the left-associativity rule is only followed when both operators have the same precedence. This is not the case when you use these operators in conjunction with keywords such as [[...]] or ((...)) or use the -o and -a operators as arguments to the test or [ commands. In such cases, AND (&& or -a) takes precedence over OR (|| or -o). Thanks to Stephane Chazelas' comment for clarifying this point.


          • It seems that in C and C-like languages && has higher precedence than || which is probably why you expected your original construct to behave like



            true || (echo aaa && echo bbb). 


            This is not the case with Bash, however, in which both operators have the same precedence, which is why Bash parses your expression using the left-associativity rule. Thanks to Kevin's comment for bringing this up.



          • There might also be cases where all 3 expressions are evaluated. If the first command returns a non-zero exit status, the || won't short circuit and goes on to execute the second command. If the second command returns with a zero exit status, then the && won't short-circuit as well and the third command will be executed. Thanks to Ignacio Vazquez-Abrams' comment for bringing this up.







          share|improve this answer





















          • 25





            A wee note to add a little more confusion: while the && and || shell operators as in cmd1 && cmd2 || cmd3 have same precedence, the && in ((...)) and [[...]] has precedence over || (((a || b && c)) is ((a || (b && c)))). Same goes for -a/-o in test/[ and find and &/| in expr.

            – Stéphane Chazelas
            Aug 30 '13 at 12:17






          • 14





            In c-like languages, && has higher precedence than ||, so the OP's expected behavior would happen. Unwary users used to such languages may not realize that in bash they have the same precedence, so it may be worth pointing out more explicitly that they do have the same precedence in bash.

            – Kevin
            Aug 30 '13 at 13:06













          • Also note that there are situations where all three commands can be run, i.e. if the middle command can return either true or false.

            – Ignacio Vazquez-Abrams
            Aug 30 '13 at 13:42











          • @Kevin Please check edited answer.

            – Joseph R.
            Aug 30 '13 at 18:51






          • 1





            Today, for me, the top Google hit for "bash operator precedence" is tldp.org/LDP/abs/html/opprecedence.html... which claims that && has a higher precedence than ||. Yet @JosephR. is clearly right de facto and de jure too. Dash behaves the same and searching for "precedence" in pubs.opengroup.org/onlinepubs/009695399/utilities/…, I see it's a POSIX requirement, so we can depend on it. All I found for bug reporting was the author's email address, which has surely been spammed to death in the last six years. I'll try anyway...

            – Martin Dorey
            Aug 21 '18 at 19:37



















          56














          If you want multiple things to depend on your condition, group them:



          true || { echo aaa && echo bbb; }


          That prints nothing, while



          true && { echo aaa && echo bbb; }


          prints both strings.





          The reason this happens is a lot more simple than Joseph is making out. Remember what Bash does with || and &&. It's all about the previous command's return status. A literal way of looking at your raw command is:



          ( true || echo aaa ) && echo bbb


          The first command (true || echo aaa) is exiting with 0.



          $ true || echo aaa; echo $?
          0
          $ true && echo aaa; echo $?
          aaa
          0

          $ false && echo aaa; echo $?
          1
          $ false || echo aaa; echo $?
          aaa
          0





          share|improve this answer





















          • 6





            +1 For achieving the OP's intended outcome. Note that the parentheses you placed in (true || echo aaa) && echo bbb is exactly what I'm making out.

            – Joseph R.
            Aug 30 '13 at 13:53






          • 1





            Nice to see @Oli in this side of the world.

            – Braiam
            Aug 30 '13 at 16:12






          • 7





            Note the semi-column ; at the very end. Without this, it will not work!

            – Serge Stroobandt
            Dec 19 '16 at 2:46








          • 2





            I was running into trouble with this because I was missing the trailing semi-colon after the last command (e.g. echo bbb; in the first examples). Once I figured out I was missing that, this answer was exactly what I was looking for. +1 for helping me figure out how to accomplish what I wanted!

            – Doktor J
            Jun 12 '17 at 18:03






          • 5





            Worth reading for anyone confused by (...) and {...} notation: command grouping manual

            – ANTARA
            Jun 4 '18 at 14:57



















          15














          The && and || operators are not exact inline replacements for if-then-else. Though if used carefully, they can accomplish much the same thing.



          A single test is straightforward and unambiguous...



          [[ A == A ]]  && echo TRUE                          # TRUE
          [[ A == B ]] && echo TRUE #
          [[ A == A ]] || echo FALSE #
          [[ A == B ]] || echo FALSE # FALSE


          However, attempting to add multiple tests may yield unexpected results...



          [[ A == A ]]  && echo TRUE   || echo FALSE          # TRUE  (as expected)
          [[ A == B ]] && echo TRUE || echo FALSE # FALSE (as expected)
          [[ A == A ]] || echo FALSE && echo TRUE # TRUE (as expected)
          [[ A == B ]] || echo FALSE && echo TRUE # FALSE TRUE (huh?)


          Why are both FALSE and TRUE echoed?



          What's happening here is that we've not realized that && and || are overloaded operators that act differently inside conditional test brackets [[ ]] than they do in the AND and OR (conditional execution) list we have here.



          From the bash manpage (edited)...




          Lists



          A list is a sequence of one or more pipelines separated by one of the
          operators ;, &, &&, or ││, and optionally terminated by one of ;, &,
          or . Of these list operators, && and ││ have equal
          precedence, followed by ; and &, which have equal precedence.



          A sequence of one or more newlines may appear in a list instead of a
          semicolon to delimit commands.



          If a command is terminated by the control operator &, the shell
          executes the command in the background in a subshell. The shell does
          not wait for the command to finish, and the return status is 0.
          Commands separated by a ; are executed sequentially; the shell waits
          for each command to terminate in turn. The return status is the exit
          status of the last command executed.



          AND and OR lists are sequences of one of more pipelines separated by
          the && and ││ control operators, respectively. AND and OR lists are
          executed with left associativity.



          An AND list has the form ...
          command1 && command2

          Command2 is executed if, and only if, command1 returns an exit status of zero.



          An OR list has the form ...
          command1 ││ command2

          Command2 is executed if and only if command1 returns a non-zero exit status.



          The return status of AND and OR lists
          is the exit status of the last command executed in the list.




          Returning to our last example...



          [[ A == B ]]  || echo FALSE  && echo TRUE

          [[ A == B ]] is false

          || Does NOT mean OR! It means...
          'execute next command if last command return code(rc) was false'

          echo FALSE The 'echo' command rc is always true
          (i.e. it successfully echoed the word "FALSE")

          && Execute next command if last command rc was true

          echo TRUE Since the 'echo FALSE' rc was true, then echo "TRUE"


          Okay. If that's correct, then why does the next to last example echo anything at all?



          [[ A == A ]]  || echo FALSE  && echo TRUE


          [[ A == A ]] is true

          || execute next command if last command rc was false.

          echo FALSE Since last rc was true, shouldn't it have stopped before this?
          Nope. Instead, it skips the 'echo FALSE', does not even try to
          execute it, and continues looking for a `&&` clause.

          && ... which it finds here

          echo TRUE ... so, since `[[ A == A ]]` is true, then it echos "TRUE"


          The risk of logic errors when using more than one && or || in a command list is quite high.



          Recommendations



          A single && or || in a command list works as expected so is pretty safe. If it's a situation where you don't need an else clause, something like the following can be clearer to follow (the curly braces are required to group the last 2 commands) ...



          [[ $1 == --help ]]  && { echo "$HELP"; exit; }


          Multiple && and || operators, where each command except for the last is a test (i.e. inside brackets [[ ]]), are usually also safe as all but the last operator behave as expected. The last operator acts more like a then or else clause.






          share|improve this answer

































            0














            I also got confused by this but here's how I think about the way Bash reads your statement (as it reads the symbols left to right):




            1. Found symbol true. This will need to be evaluated once the end of the command is reached. At this point, don't know if it has any arguments. Store command in execution buffer.

            2. Found symbol ||. Previous command is now complete, so evaluate it. Command (buffer) being executed: true. Result of evaluation: 0 (i.e. success). Store result 0 in "last evaluation" register. Now consider symbol || itself. This depends on the result of the last evaluation being non-zero. Checked "last evaluation" register and found 0. Since 0 is not non-zero, the following command does not need to be evaluated.

            3. Found symbol echo. Can ignore this symbol, because the following command did not need to be evaluated.

            4. Found symbol aaa. This is an argument to command echo (3), but since echo (3) did not need to be evaluated, it can be ignored.

            5. Found symbol &&. This depends on the result of the last evaluation being zero. Checked "last evaluation" register and found 0. Since 0 is zero, the following command does need to be evaluated.

            6. Found symbol echo. This command needs to be evaluated once the end of the command is reached, because the following command did need to be evaluated. Store command in execution buffer.

            7. Found symbol bbb. This is an argument to command echo (6). Since echo did need to be evaluated, add bbb to execution buffer.

            8. Reached end of line. Previous command is now complete and did need to be evaluated. Command (buffer) being executed: echo bbb. Result of evaluation: 0 (i.e. success). Store result 0 in "last evaluation" register.


            And of course, the last step causes bbb to be echoed to the console.






            share|improve this answer























              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
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f88850%2fprecedence-of-the-shell-logical-operators%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









              110














              In many computer languages, operators with the same precedence are left-associative. That is, in the absence of grouping structures, leftmost operations are executed first. Bash is no exception to this rule.



              This is important because, in Bash, && and || have the same precedence.



              So what happens in your example is that the leftmost operation (||) is carried out first:



              true || echo aaa


              Since true is obviously true, the || operator short-circuits and the whole statement is considered true without the need to evaluate echo aaa as you would expect. Now it remains to do the rightmost operation:



              (...) && echo bbb


              Since the first operation evaluated to true (i.e. had a 0 exit status), it's as if you're executing



              true && echo bbb


              so the && will not short-circuit, which is why you see bbb echoed.



              You would get the same behavior with



              false && echo aaa || echo bbb


              Notes based on the comments




              • You should note that the left-associativity rule is only followed when both operators have the same precedence. This is not the case when you use these operators in conjunction with keywords such as [[...]] or ((...)) or use the -o and -a operators as arguments to the test or [ commands. In such cases, AND (&& or -a) takes precedence over OR (|| or -o). Thanks to Stephane Chazelas' comment for clarifying this point.


              • It seems that in C and C-like languages && has higher precedence than || which is probably why you expected your original construct to behave like



                true || (echo aaa && echo bbb). 


                This is not the case with Bash, however, in which both operators have the same precedence, which is why Bash parses your expression using the left-associativity rule. Thanks to Kevin's comment for bringing this up.



              • There might also be cases where all 3 expressions are evaluated. If the first command returns a non-zero exit status, the || won't short circuit and goes on to execute the second command. If the second command returns with a zero exit status, then the && won't short-circuit as well and the third command will be executed. Thanks to Ignacio Vazquez-Abrams' comment for bringing this up.







              share|improve this answer





















              • 25





                A wee note to add a little more confusion: while the && and || shell operators as in cmd1 && cmd2 || cmd3 have same precedence, the && in ((...)) and [[...]] has precedence over || (((a || b && c)) is ((a || (b && c)))). Same goes for -a/-o in test/[ and find and &/| in expr.

                – Stéphane Chazelas
                Aug 30 '13 at 12:17






              • 14





                In c-like languages, && has higher precedence than ||, so the OP's expected behavior would happen. Unwary users used to such languages may not realize that in bash they have the same precedence, so it may be worth pointing out more explicitly that they do have the same precedence in bash.

                – Kevin
                Aug 30 '13 at 13:06













              • Also note that there are situations where all three commands can be run, i.e. if the middle command can return either true or false.

                – Ignacio Vazquez-Abrams
                Aug 30 '13 at 13:42











              • @Kevin Please check edited answer.

                – Joseph R.
                Aug 30 '13 at 18:51






              • 1





                Today, for me, the top Google hit for "bash operator precedence" is tldp.org/LDP/abs/html/opprecedence.html... which claims that && has a higher precedence than ||. Yet @JosephR. is clearly right de facto and de jure too. Dash behaves the same and searching for "precedence" in pubs.opengroup.org/onlinepubs/009695399/utilities/…, I see it's a POSIX requirement, so we can depend on it. All I found for bug reporting was the author's email address, which has surely been spammed to death in the last six years. I'll try anyway...

                – Martin Dorey
                Aug 21 '18 at 19:37
















              110














              In many computer languages, operators with the same precedence are left-associative. That is, in the absence of grouping structures, leftmost operations are executed first. Bash is no exception to this rule.



              This is important because, in Bash, && and || have the same precedence.



              So what happens in your example is that the leftmost operation (||) is carried out first:



              true || echo aaa


              Since true is obviously true, the || operator short-circuits and the whole statement is considered true without the need to evaluate echo aaa as you would expect. Now it remains to do the rightmost operation:



              (...) && echo bbb


              Since the first operation evaluated to true (i.e. had a 0 exit status), it's as if you're executing



              true && echo bbb


              so the && will not short-circuit, which is why you see bbb echoed.



              You would get the same behavior with



              false && echo aaa || echo bbb


              Notes based on the comments




              • You should note that the left-associativity rule is only followed when both operators have the same precedence. This is not the case when you use these operators in conjunction with keywords such as [[...]] or ((...)) or use the -o and -a operators as arguments to the test or [ commands. In such cases, AND (&& or -a) takes precedence over OR (|| or -o). Thanks to Stephane Chazelas' comment for clarifying this point.


              • It seems that in C and C-like languages && has higher precedence than || which is probably why you expected your original construct to behave like



                true || (echo aaa && echo bbb). 


                This is not the case with Bash, however, in which both operators have the same precedence, which is why Bash parses your expression using the left-associativity rule. Thanks to Kevin's comment for bringing this up.



              • There might also be cases where all 3 expressions are evaluated. If the first command returns a non-zero exit status, the || won't short circuit and goes on to execute the second command. If the second command returns with a zero exit status, then the && won't short-circuit as well and the third command will be executed. Thanks to Ignacio Vazquez-Abrams' comment for bringing this up.







              share|improve this answer





















              • 25





                A wee note to add a little more confusion: while the && and || shell operators as in cmd1 && cmd2 || cmd3 have same precedence, the && in ((...)) and [[...]] has precedence over || (((a || b && c)) is ((a || (b && c)))). Same goes for -a/-o in test/[ and find and &/| in expr.

                – Stéphane Chazelas
                Aug 30 '13 at 12:17






              • 14





                In c-like languages, && has higher precedence than ||, so the OP's expected behavior would happen. Unwary users used to such languages may not realize that in bash they have the same precedence, so it may be worth pointing out more explicitly that they do have the same precedence in bash.

                – Kevin
                Aug 30 '13 at 13:06













              • Also note that there are situations where all three commands can be run, i.e. if the middle command can return either true or false.

                – Ignacio Vazquez-Abrams
                Aug 30 '13 at 13:42











              • @Kevin Please check edited answer.

                – Joseph R.
                Aug 30 '13 at 18:51






              • 1





                Today, for me, the top Google hit for "bash operator precedence" is tldp.org/LDP/abs/html/opprecedence.html... which claims that && has a higher precedence than ||. Yet @JosephR. is clearly right de facto and de jure too. Dash behaves the same and searching for "precedence" in pubs.opengroup.org/onlinepubs/009695399/utilities/…, I see it's a POSIX requirement, so we can depend on it. All I found for bug reporting was the author's email address, which has surely been spammed to death in the last six years. I'll try anyway...

                – Martin Dorey
                Aug 21 '18 at 19:37














              110












              110








              110







              In many computer languages, operators with the same precedence are left-associative. That is, in the absence of grouping structures, leftmost operations are executed first. Bash is no exception to this rule.



              This is important because, in Bash, && and || have the same precedence.



              So what happens in your example is that the leftmost operation (||) is carried out first:



              true || echo aaa


              Since true is obviously true, the || operator short-circuits and the whole statement is considered true without the need to evaluate echo aaa as you would expect. Now it remains to do the rightmost operation:



              (...) && echo bbb


              Since the first operation evaluated to true (i.e. had a 0 exit status), it's as if you're executing



              true && echo bbb


              so the && will not short-circuit, which is why you see bbb echoed.



              You would get the same behavior with



              false && echo aaa || echo bbb


              Notes based on the comments




              • You should note that the left-associativity rule is only followed when both operators have the same precedence. This is not the case when you use these operators in conjunction with keywords such as [[...]] or ((...)) or use the -o and -a operators as arguments to the test or [ commands. In such cases, AND (&& or -a) takes precedence over OR (|| or -o). Thanks to Stephane Chazelas' comment for clarifying this point.


              • It seems that in C and C-like languages && has higher precedence than || which is probably why you expected your original construct to behave like



                true || (echo aaa && echo bbb). 


                This is not the case with Bash, however, in which both operators have the same precedence, which is why Bash parses your expression using the left-associativity rule. Thanks to Kevin's comment for bringing this up.



              • There might also be cases where all 3 expressions are evaluated. If the first command returns a non-zero exit status, the || won't short circuit and goes on to execute the second command. If the second command returns with a zero exit status, then the && won't short-circuit as well and the third command will be executed. Thanks to Ignacio Vazquez-Abrams' comment for bringing this up.







              share|improve this answer















              In many computer languages, operators with the same precedence are left-associative. That is, in the absence of grouping structures, leftmost operations are executed first. Bash is no exception to this rule.



              This is important because, in Bash, && and || have the same precedence.



              So what happens in your example is that the leftmost operation (||) is carried out first:



              true || echo aaa


              Since true is obviously true, the || operator short-circuits and the whole statement is considered true without the need to evaluate echo aaa as you would expect. Now it remains to do the rightmost operation:



              (...) && echo bbb


              Since the first operation evaluated to true (i.e. had a 0 exit status), it's as if you're executing



              true && echo bbb


              so the && will not short-circuit, which is why you see bbb echoed.



              You would get the same behavior with



              false && echo aaa || echo bbb


              Notes based on the comments




              • You should note that the left-associativity rule is only followed when both operators have the same precedence. This is not the case when you use these operators in conjunction with keywords such as [[...]] or ((...)) or use the -o and -a operators as arguments to the test or [ commands. In such cases, AND (&& or -a) takes precedence over OR (|| or -o). Thanks to Stephane Chazelas' comment for clarifying this point.


              • It seems that in C and C-like languages && has higher precedence than || which is probably why you expected your original construct to behave like



                true || (echo aaa && echo bbb). 


                This is not the case with Bash, however, in which both operators have the same precedence, which is why Bash parses your expression using the left-associativity rule. Thanks to Kevin's comment for bringing this up.



              • There might also be cases where all 3 expressions are evaluated. If the first command returns a non-zero exit status, the || won't short circuit and goes on to execute the second command. If the second command returns with a zero exit status, then the && won't short-circuit as well and the third command will be executed. Thanks to Ignacio Vazquez-Abrams' comment for bringing this up.








              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Sep 1 '13 at 15:23

























              answered Aug 30 '13 at 11:26









              Joseph R.Joseph R.

              28.5k375116




              28.5k375116








              • 25





                A wee note to add a little more confusion: while the && and || shell operators as in cmd1 && cmd2 || cmd3 have same precedence, the && in ((...)) and [[...]] has precedence over || (((a || b && c)) is ((a || (b && c)))). Same goes for -a/-o in test/[ and find and &/| in expr.

                – Stéphane Chazelas
                Aug 30 '13 at 12:17






              • 14





                In c-like languages, && has higher precedence than ||, so the OP's expected behavior would happen. Unwary users used to such languages may not realize that in bash they have the same precedence, so it may be worth pointing out more explicitly that they do have the same precedence in bash.

                – Kevin
                Aug 30 '13 at 13:06













              • Also note that there are situations where all three commands can be run, i.e. if the middle command can return either true or false.

                – Ignacio Vazquez-Abrams
                Aug 30 '13 at 13:42











              • @Kevin Please check edited answer.

                – Joseph R.
                Aug 30 '13 at 18:51






              • 1





                Today, for me, the top Google hit for "bash operator precedence" is tldp.org/LDP/abs/html/opprecedence.html... which claims that && has a higher precedence than ||. Yet @JosephR. is clearly right de facto and de jure too. Dash behaves the same and searching for "precedence" in pubs.opengroup.org/onlinepubs/009695399/utilities/…, I see it's a POSIX requirement, so we can depend on it. All I found for bug reporting was the author's email address, which has surely been spammed to death in the last six years. I'll try anyway...

                – Martin Dorey
                Aug 21 '18 at 19:37














              • 25





                A wee note to add a little more confusion: while the && and || shell operators as in cmd1 && cmd2 || cmd3 have same precedence, the && in ((...)) and [[...]] has precedence over || (((a || b && c)) is ((a || (b && c)))). Same goes for -a/-o in test/[ and find and &/| in expr.

                – Stéphane Chazelas
                Aug 30 '13 at 12:17






              • 14





                In c-like languages, && has higher precedence than ||, so the OP's expected behavior would happen. Unwary users used to such languages may not realize that in bash they have the same precedence, so it may be worth pointing out more explicitly that they do have the same precedence in bash.

                – Kevin
                Aug 30 '13 at 13:06













              • Also note that there are situations where all three commands can be run, i.e. if the middle command can return either true or false.

                – Ignacio Vazquez-Abrams
                Aug 30 '13 at 13:42











              • @Kevin Please check edited answer.

                – Joseph R.
                Aug 30 '13 at 18:51






              • 1





                Today, for me, the top Google hit for "bash operator precedence" is tldp.org/LDP/abs/html/opprecedence.html... which claims that && has a higher precedence than ||. Yet @JosephR. is clearly right de facto and de jure too. Dash behaves the same and searching for "precedence" in pubs.opengroup.org/onlinepubs/009695399/utilities/…, I see it's a POSIX requirement, so we can depend on it. All I found for bug reporting was the author's email address, which has surely been spammed to death in the last six years. I'll try anyway...

                – Martin Dorey
                Aug 21 '18 at 19:37








              25




              25





              A wee note to add a little more confusion: while the && and || shell operators as in cmd1 && cmd2 || cmd3 have same precedence, the && in ((...)) and [[...]] has precedence over || (((a || b && c)) is ((a || (b && c)))). Same goes for -a/-o in test/[ and find and &/| in expr.

              – Stéphane Chazelas
              Aug 30 '13 at 12:17





              A wee note to add a little more confusion: while the && and || shell operators as in cmd1 && cmd2 || cmd3 have same precedence, the && in ((...)) and [[...]] has precedence over || (((a || b && c)) is ((a || (b && c)))). Same goes for -a/-o in test/[ and find and &/| in expr.

              – Stéphane Chazelas
              Aug 30 '13 at 12:17




              14




              14





              In c-like languages, && has higher precedence than ||, so the OP's expected behavior would happen. Unwary users used to such languages may not realize that in bash they have the same precedence, so it may be worth pointing out more explicitly that they do have the same precedence in bash.

              – Kevin
              Aug 30 '13 at 13:06







              In c-like languages, && has higher precedence than ||, so the OP's expected behavior would happen. Unwary users used to such languages may not realize that in bash they have the same precedence, so it may be worth pointing out more explicitly that they do have the same precedence in bash.

              – Kevin
              Aug 30 '13 at 13:06















              Also note that there are situations where all three commands can be run, i.e. if the middle command can return either true or false.

              – Ignacio Vazquez-Abrams
              Aug 30 '13 at 13:42





              Also note that there are situations where all three commands can be run, i.e. if the middle command can return either true or false.

              – Ignacio Vazquez-Abrams
              Aug 30 '13 at 13:42













              @Kevin Please check edited answer.

              – Joseph R.
              Aug 30 '13 at 18:51





              @Kevin Please check edited answer.

              – Joseph R.
              Aug 30 '13 at 18:51




              1




              1





              Today, for me, the top Google hit for "bash operator precedence" is tldp.org/LDP/abs/html/opprecedence.html... which claims that && has a higher precedence than ||. Yet @JosephR. is clearly right de facto and de jure too. Dash behaves the same and searching for "precedence" in pubs.opengroup.org/onlinepubs/009695399/utilities/…, I see it's a POSIX requirement, so we can depend on it. All I found for bug reporting was the author's email address, which has surely been spammed to death in the last six years. I'll try anyway...

              – Martin Dorey
              Aug 21 '18 at 19:37





              Today, for me, the top Google hit for "bash operator precedence" is tldp.org/LDP/abs/html/opprecedence.html... which claims that && has a higher precedence than ||. Yet @JosephR. is clearly right de facto and de jure too. Dash behaves the same and searching for "precedence" in pubs.opengroup.org/onlinepubs/009695399/utilities/…, I see it's a POSIX requirement, so we can depend on it. All I found for bug reporting was the author's email address, which has surely been spammed to death in the last six years. I'll try anyway...

              – Martin Dorey
              Aug 21 '18 at 19:37













              56














              If you want multiple things to depend on your condition, group them:



              true || { echo aaa && echo bbb; }


              That prints nothing, while



              true && { echo aaa && echo bbb; }


              prints both strings.





              The reason this happens is a lot more simple than Joseph is making out. Remember what Bash does with || and &&. It's all about the previous command's return status. A literal way of looking at your raw command is:



              ( true || echo aaa ) && echo bbb


              The first command (true || echo aaa) is exiting with 0.



              $ true || echo aaa; echo $?
              0
              $ true && echo aaa; echo $?
              aaa
              0

              $ false && echo aaa; echo $?
              1
              $ false || echo aaa; echo $?
              aaa
              0





              share|improve this answer





















              • 6





                +1 For achieving the OP's intended outcome. Note that the parentheses you placed in (true || echo aaa) && echo bbb is exactly what I'm making out.

                – Joseph R.
                Aug 30 '13 at 13:53






              • 1





                Nice to see @Oli in this side of the world.

                – Braiam
                Aug 30 '13 at 16:12






              • 7





                Note the semi-column ; at the very end. Without this, it will not work!

                – Serge Stroobandt
                Dec 19 '16 at 2:46








              • 2





                I was running into trouble with this because I was missing the trailing semi-colon after the last command (e.g. echo bbb; in the first examples). Once I figured out I was missing that, this answer was exactly what I was looking for. +1 for helping me figure out how to accomplish what I wanted!

                – Doktor J
                Jun 12 '17 at 18:03






              • 5





                Worth reading for anyone confused by (...) and {...} notation: command grouping manual

                – ANTARA
                Jun 4 '18 at 14:57
















              56














              If you want multiple things to depend on your condition, group them:



              true || { echo aaa && echo bbb; }


              That prints nothing, while



              true && { echo aaa && echo bbb; }


              prints both strings.





              The reason this happens is a lot more simple than Joseph is making out. Remember what Bash does with || and &&. It's all about the previous command's return status. A literal way of looking at your raw command is:



              ( true || echo aaa ) && echo bbb


              The first command (true || echo aaa) is exiting with 0.



              $ true || echo aaa; echo $?
              0
              $ true && echo aaa; echo $?
              aaa
              0

              $ false && echo aaa; echo $?
              1
              $ false || echo aaa; echo $?
              aaa
              0





              share|improve this answer





















              • 6





                +1 For achieving the OP's intended outcome. Note that the parentheses you placed in (true || echo aaa) && echo bbb is exactly what I'm making out.

                – Joseph R.
                Aug 30 '13 at 13:53






              • 1





                Nice to see @Oli in this side of the world.

                – Braiam
                Aug 30 '13 at 16:12






              • 7





                Note the semi-column ; at the very end. Without this, it will not work!

                – Serge Stroobandt
                Dec 19 '16 at 2:46








              • 2





                I was running into trouble with this because I was missing the trailing semi-colon after the last command (e.g. echo bbb; in the first examples). Once I figured out I was missing that, this answer was exactly what I was looking for. +1 for helping me figure out how to accomplish what I wanted!

                – Doktor J
                Jun 12 '17 at 18:03






              • 5





                Worth reading for anyone confused by (...) and {...} notation: command grouping manual

                – ANTARA
                Jun 4 '18 at 14:57














              56












              56








              56







              If you want multiple things to depend on your condition, group them:



              true || { echo aaa && echo bbb; }


              That prints nothing, while



              true && { echo aaa && echo bbb; }


              prints both strings.





              The reason this happens is a lot more simple than Joseph is making out. Remember what Bash does with || and &&. It's all about the previous command's return status. A literal way of looking at your raw command is:



              ( true || echo aaa ) && echo bbb


              The first command (true || echo aaa) is exiting with 0.



              $ true || echo aaa; echo $?
              0
              $ true && echo aaa; echo $?
              aaa
              0

              $ false && echo aaa; echo $?
              1
              $ false || echo aaa; echo $?
              aaa
              0





              share|improve this answer















              If you want multiple things to depend on your condition, group them:



              true || { echo aaa && echo bbb; }


              That prints nothing, while



              true && { echo aaa && echo bbb; }


              prints both strings.





              The reason this happens is a lot more simple than Joseph is making out. Remember what Bash does with || and &&. It's all about the previous command's return status. A literal way of looking at your raw command is:



              ( true || echo aaa ) && echo bbb


              The first command (true || echo aaa) is exiting with 0.



              $ true || echo aaa; echo $?
              0
              $ true && echo aaa; echo $?
              aaa
              0

              $ false && echo aaa; echo $?
              1
              $ false || echo aaa; echo $?
              aaa
              0






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Nov 12 '18 at 22:56









              Avi Flax

              1035




              1035










              answered Aug 30 '13 at 13:27









              OliOli

              7,68063248




              7,68063248








              • 6





                +1 For achieving the OP's intended outcome. Note that the parentheses you placed in (true || echo aaa) && echo bbb is exactly what I'm making out.

                – Joseph R.
                Aug 30 '13 at 13:53






              • 1





                Nice to see @Oli in this side of the world.

                – Braiam
                Aug 30 '13 at 16:12






              • 7





                Note the semi-column ; at the very end. Without this, it will not work!

                – Serge Stroobandt
                Dec 19 '16 at 2:46








              • 2





                I was running into trouble with this because I was missing the trailing semi-colon after the last command (e.g. echo bbb; in the first examples). Once I figured out I was missing that, this answer was exactly what I was looking for. +1 for helping me figure out how to accomplish what I wanted!

                – Doktor J
                Jun 12 '17 at 18:03






              • 5





                Worth reading for anyone confused by (...) and {...} notation: command grouping manual

                – ANTARA
                Jun 4 '18 at 14:57














              • 6





                +1 For achieving the OP's intended outcome. Note that the parentheses you placed in (true || echo aaa) && echo bbb is exactly what I'm making out.

                – Joseph R.
                Aug 30 '13 at 13:53






              • 1





                Nice to see @Oli in this side of the world.

                – Braiam
                Aug 30 '13 at 16:12






              • 7





                Note the semi-column ; at the very end. Without this, it will not work!

                – Serge Stroobandt
                Dec 19 '16 at 2:46








              • 2





                I was running into trouble with this because I was missing the trailing semi-colon after the last command (e.g. echo bbb; in the first examples). Once I figured out I was missing that, this answer was exactly what I was looking for. +1 for helping me figure out how to accomplish what I wanted!

                – Doktor J
                Jun 12 '17 at 18:03






              • 5





                Worth reading for anyone confused by (...) and {...} notation: command grouping manual

                – ANTARA
                Jun 4 '18 at 14:57








              6




              6





              +1 For achieving the OP's intended outcome. Note that the parentheses you placed in (true || echo aaa) && echo bbb is exactly what I'm making out.

              – Joseph R.
              Aug 30 '13 at 13:53





              +1 For achieving the OP's intended outcome. Note that the parentheses you placed in (true || echo aaa) && echo bbb is exactly what I'm making out.

              – Joseph R.
              Aug 30 '13 at 13:53




              1




              1





              Nice to see @Oli in this side of the world.

              – Braiam
              Aug 30 '13 at 16:12





              Nice to see @Oli in this side of the world.

              – Braiam
              Aug 30 '13 at 16:12




              7




              7





              Note the semi-column ; at the very end. Without this, it will not work!

              – Serge Stroobandt
              Dec 19 '16 at 2:46







              Note the semi-column ; at the very end. Without this, it will not work!

              – Serge Stroobandt
              Dec 19 '16 at 2:46






              2




              2





              I was running into trouble with this because I was missing the trailing semi-colon after the last command (e.g. echo bbb; in the first examples). Once I figured out I was missing that, this answer was exactly what I was looking for. +1 for helping me figure out how to accomplish what I wanted!

              – Doktor J
              Jun 12 '17 at 18:03





              I was running into trouble with this because I was missing the trailing semi-colon after the last command (e.g. echo bbb; in the first examples). Once I figured out I was missing that, this answer was exactly what I was looking for. +1 for helping me figure out how to accomplish what I wanted!

              – Doktor J
              Jun 12 '17 at 18:03




              5




              5





              Worth reading for anyone confused by (...) and {...} notation: command grouping manual

              – ANTARA
              Jun 4 '18 at 14:57





              Worth reading for anyone confused by (...) and {...} notation: command grouping manual

              – ANTARA
              Jun 4 '18 at 14:57











              15














              The && and || operators are not exact inline replacements for if-then-else. Though if used carefully, they can accomplish much the same thing.



              A single test is straightforward and unambiguous...



              [[ A == A ]]  && echo TRUE                          # TRUE
              [[ A == B ]] && echo TRUE #
              [[ A == A ]] || echo FALSE #
              [[ A == B ]] || echo FALSE # FALSE


              However, attempting to add multiple tests may yield unexpected results...



              [[ A == A ]]  && echo TRUE   || echo FALSE          # TRUE  (as expected)
              [[ A == B ]] && echo TRUE || echo FALSE # FALSE (as expected)
              [[ A == A ]] || echo FALSE && echo TRUE # TRUE (as expected)
              [[ A == B ]] || echo FALSE && echo TRUE # FALSE TRUE (huh?)


              Why are both FALSE and TRUE echoed?



              What's happening here is that we've not realized that && and || are overloaded operators that act differently inside conditional test brackets [[ ]] than they do in the AND and OR (conditional execution) list we have here.



              From the bash manpage (edited)...




              Lists



              A list is a sequence of one or more pipelines separated by one of the
              operators ;, &, &&, or ││, and optionally terminated by one of ;, &,
              or . Of these list operators, && and ││ have equal
              precedence, followed by ; and &, which have equal precedence.



              A sequence of one or more newlines may appear in a list instead of a
              semicolon to delimit commands.



              If a command is terminated by the control operator &, the shell
              executes the command in the background in a subshell. The shell does
              not wait for the command to finish, and the return status is 0.
              Commands separated by a ; are executed sequentially; the shell waits
              for each command to terminate in turn. The return status is the exit
              status of the last command executed.



              AND and OR lists are sequences of one of more pipelines separated by
              the && and ││ control operators, respectively. AND and OR lists are
              executed with left associativity.



              An AND list has the form ...
              command1 && command2

              Command2 is executed if, and only if, command1 returns an exit status of zero.



              An OR list has the form ...
              command1 ││ command2

              Command2 is executed if and only if command1 returns a non-zero exit status.



              The return status of AND and OR lists
              is the exit status of the last command executed in the list.




              Returning to our last example...



              [[ A == B ]]  || echo FALSE  && echo TRUE

              [[ A == B ]] is false

              || Does NOT mean OR! It means...
              'execute next command if last command return code(rc) was false'

              echo FALSE The 'echo' command rc is always true
              (i.e. it successfully echoed the word "FALSE")

              && Execute next command if last command rc was true

              echo TRUE Since the 'echo FALSE' rc was true, then echo "TRUE"


              Okay. If that's correct, then why does the next to last example echo anything at all?



              [[ A == A ]]  || echo FALSE  && echo TRUE


              [[ A == A ]] is true

              || execute next command if last command rc was false.

              echo FALSE Since last rc was true, shouldn't it have stopped before this?
              Nope. Instead, it skips the 'echo FALSE', does not even try to
              execute it, and continues looking for a `&&` clause.

              && ... which it finds here

              echo TRUE ... so, since `[[ A == A ]]` is true, then it echos "TRUE"


              The risk of logic errors when using more than one && or || in a command list is quite high.



              Recommendations



              A single && or || in a command list works as expected so is pretty safe. If it's a situation where you don't need an else clause, something like the following can be clearer to follow (the curly braces are required to group the last 2 commands) ...



              [[ $1 == --help ]]  && { echo "$HELP"; exit; }


              Multiple && and || operators, where each command except for the last is a test (i.e. inside brackets [[ ]]), are usually also safe as all but the last operator behave as expected. The last operator acts more like a then or else clause.






              share|improve this answer






























                15














                The && and || operators are not exact inline replacements for if-then-else. Though if used carefully, they can accomplish much the same thing.



                A single test is straightforward and unambiguous...



                [[ A == A ]]  && echo TRUE                          # TRUE
                [[ A == B ]] && echo TRUE #
                [[ A == A ]] || echo FALSE #
                [[ A == B ]] || echo FALSE # FALSE


                However, attempting to add multiple tests may yield unexpected results...



                [[ A == A ]]  && echo TRUE   || echo FALSE          # TRUE  (as expected)
                [[ A == B ]] && echo TRUE || echo FALSE # FALSE (as expected)
                [[ A == A ]] || echo FALSE && echo TRUE # TRUE (as expected)
                [[ A == B ]] || echo FALSE && echo TRUE # FALSE TRUE (huh?)


                Why are both FALSE and TRUE echoed?



                What's happening here is that we've not realized that && and || are overloaded operators that act differently inside conditional test brackets [[ ]] than they do in the AND and OR (conditional execution) list we have here.



                From the bash manpage (edited)...




                Lists



                A list is a sequence of one or more pipelines separated by one of the
                operators ;, &, &&, or ││, and optionally terminated by one of ;, &,
                or . Of these list operators, && and ││ have equal
                precedence, followed by ; and &, which have equal precedence.



                A sequence of one or more newlines may appear in a list instead of a
                semicolon to delimit commands.



                If a command is terminated by the control operator &, the shell
                executes the command in the background in a subshell. The shell does
                not wait for the command to finish, and the return status is 0.
                Commands separated by a ; are executed sequentially; the shell waits
                for each command to terminate in turn. The return status is the exit
                status of the last command executed.



                AND and OR lists are sequences of one of more pipelines separated by
                the && and ││ control operators, respectively. AND and OR lists are
                executed with left associativity.



                An AND list has the form ...
                command1 && command2

                Command2 is executed if, and only if, command1 returns an exit status of zero.



                An OR list has the form ...
                command1 ││ command2

                Command2 is executed if and only if command1 returns a non-zero exit status.



                The return status of AND and OR lists
                is the exit status of the last command executed in the list.




                Returning to our last example...



                [[ A == B ]]  || echo FALSE  && echo TRUE

                [[ A == B ]] is false

                || Does NOT mean OR! It means...
                'execute next command if last command return code(rc) was false'

                echo FALSE The 'echo' command rc is always true
                (i.e. it successfully echoed the word "FALSE")

                && Execute next command if last command rc was true

                echo TRUE Since the 'echo FALSE' rc was true, then echo "TRUE"


                Okay. If that's correct, then why does the next to last example echo anything at all?



                [[ A == A ]]  || echo FALSE  && echo TRUE


                [[ A == A ]] is true

                || execute next command if last command rc was false.

                echo FALSE Since last rc was true, shouldn't it have stopped before this?
                Nope. Instead, it skips the 'echo FALSE', does not even try to
                execute it, and continues looking for a `&&` clause.

                && ... which it finds here

                echo TRUE ... so, since `[[ A == A ]]` is true, then it echos "TRUE"


                The risk of logic errors when using more than one && or || in a command list is quite high.



                Recommendations



                A single && or || in a command list works as expected so is pretty safe. If it's a situation where you don't need an else clause, something like the following can be clearer to follow (the curly braces are required to group the last 2 commands) ...



                [[ $1 == --help ]]  && { echo "$HELP"; exit; }


                Multiple && and || operators, where each command except for the last is a test (i.e. inside brackets [[ ]]), are usually also safe as all but the last operator behave as expected. The last operator acts more like a then or else clause.






                share|improve this answer




























                  15












                  15








                  15







                  The && and || operators are not exact inline replacements for if-then-else. Though if used carefully, they can accomplish much the same thing.



                  A single test is straightforward and unambiguous...



                  [[ A == A ]]  && echo TRUE                          # TRUE
                  [[ A == B ]] && echo TRUE #
                  [[ A == A ]] || echo FALSE #
                  [[ A == B ]] || echo FALSE # FALSE


                  However, attempting to add multiple tests may yield unexpected results...



                  [[ A == A ]]  && echo TRUE   || echo FALSE          # TRUE  (as expected)
                  [[ A == B ]] && echo TRUE || echo FALSE # FALSE (as expected)
                  [[ A == A ]] || echo FALSE && echo TRUE # TRUE (as expected)
                  [[ A == B ]] || echo FALSE && echo TRUE # FALSE TRUE (huh?)


                  Why are both FALSE and TRUE echoed?



                  What's happening here is that we've not realized that && and || are overloaded operators that act differently inside conditional test brackets [[ ]] than they do in the AND and OR (conditional execution) list we have here.



                  From the bash manpage (edited)...




                  Lists



                  A list is a sequence of one or more pipelines separated by one of the
                  operators ;, &, &&, or ││, and optionally terminated by one of ;, &,
                  or . Of these list operators, && and ││ have equal
                  precedence, followed by ; and &, which have equal precedence.



                  A sequence of one or more newlines may appear in a list instead of a
                  semicolon to delimit commands.



                  If a command is terminated by the control operator &, the shell
                  executes the command in the background in a subshell. The shell does
                  not wait for the command to finish, and the return status is 0.
                  Commands separated by a ; are executed sequentially; the shell waits
                  for each command to terminate in turn. The return status is the exit
                  status of the last command executed.



                  AND and OR lists are sequences of one of more pipelines separated by
                  the && and ││ control operators, respectively. AND and OR lists are
                  executed with left associativity.



                  An AND list has the form ...
                  command1 && command2

                  Command2 is executed if, and only if, command1 returns an exit status of zero.



                  An OR list has the form ...
                  command1 ││ command2

                  Command2 is executed if and only if command1 returns a non-zero exit status.



                  The return status of AND and OR lists
                  is the exit status of the last command executed in the list.




                  Returning to our last example...



                  [[ A == B ]]  || echo FALSE  && echo TRUE

                  [[ A == B ]] is false

                  || Does NOT mean OR! It means...
                  'execute next command if last command return code(rc) was false'

                  echo FALSE The 'echo' command rc is always true
                  (i.e. it successfully echoed the word "FALSE")

                  && Execute next command if last command rc was true

                  echo TRUE Since the 'echo FALSE' rc was true, then echo "TRUE"


                  Okay. If that's correct, then why does the next to last example echo anything at all?



                  [[ A == A ]]  || echo FALSE  && echo TRUE


                  [[ A == A ]] is true

                  || execute next command if last command rc was false.

                  echo FALSE Since last rc was true, shouldn't it have stopped before this?
                  Nope. Instead, it skips the 'echo FALSE', does not even try to
                  execute it, and continues looking for a `&&` clause.

                  && ... which it finds here

                  echo TRUE ... so, since `[[ A == A ]]` is true, then it echos "TRUE"


                  The risk of logic errors when using more than one && or || in a command list is quite high.



                  Recommendations



                  A single && or || in a command list works as expected so is pretty safe. If it's a situation where you don't need an else clause, something like the following can be clearer to follow (the curly braces are required to group the last 2 commands) ...



                  [[ $1 == --help ]]  && { echo "$HELP"; exit; }


                  Multiple && and || operators, where each command except for the last is a test (i.e. inside brackets [[ ]]), are usually also safe as all but the last operator behave as expected. The last operator acts more like a then or else clause.






                  share|improve this answer















                  The && and || operators are not exact inline replacements for if-then-else. Though if used carefully, they can accomplish much the same thing.



                  A single test is straightforward and unambiguous...



                  [[ A == A ]]  && echo TRUE                          # TRUE
                  [[ A == B ]] && echo TRUE #
                  [[ A == A ]] || echo FALSE #
                  [[ A == B ]] || echo FALSE # FALSE


                  However, attempting to add multiple tests may yield unexpected results...



                  [[ A == A ]]  && echo TRUE   || echo FALSE          # TRUE  (as expected)
                  [[ A == B ]] && echo TRUE || echo FALSE # FALSE (as expected)
                  [[ A == A ]] || echo FALSE && echo TRUE # TRUE (as expected)
                  [[ A == B ]] || echo FALSE && echo TRUE # FALSE TRUE (huh?)


                  Why are both FALSE and TRUE echoed?



                  What's happening here is that we've not realized that && and || are overloaded operators that act differently inside conditional test brackets [[ ]] than they do in the AND and OR (conditional execution) list we have here.



                  From the bash manpage (edited)...




                  Lists



                  A list is a sequence of one or more pipelines separated by one of the
                  operators ;, &, &&, or ││, and optionally terminated by one of ;, &,
                  or . Of these list operators, && and ││ have equal
                  precedence, followed by ; and &, which have equal precedence.



                  A sequence of one or more newlines may appear in a list instead of a
                  semicolon to delimit commands.



                  If a command is terminated by the control operator &, the shell
                  executes the command in the background in a subshell. The shell does
                  not wait for the command to finish, and the return status is 0.
                  Commands separated by a ; are executed sequentially; the shell waits
                  for each command to terminate in turn. The return status is the exit
                  status of the last command executed.



                  AND and OR lists are sequences of one of more pipelines separated by
                  the && and ││ control operators, respectively. AND and OR lists are
                  executed with left associativity.



                  An AND list has the form ...
                  command1 && command2

                  Command2 is executed if, and only if, command1 returns an exit status of zero.



                  An OR list has the form ...
                  command1 ││ command2

                  Command2 is executed if and only if command1 returns a non-zero exit status.



                  The return status of AND and OR lists
                  is the exit status of the last command executed in the list.




                  Returning to our last example...



                  [[ A == B ]]  || echo FALSE  && echo TRUE

                  [[ A == B ]] is false

                  || Does NOT mean OR! It means...
                  'execute next command if last command return code(rc) was false'

                  echo FALSE The 'echo' command rc is always true
                  (i.e. it successfully echoed the word "FALSE")

                  && Execute next command if last command rc was true

                  echo TRUE Since the 'echo FALSE' rc was true, then echo "TRUE"


                  Okay. If that's correct, then why does the next to last example echo anything at all?



                  [[ A == A ]]  || echo FALSE  && echo TRUE


                  [[ A == A ]] is true

                  || execute next command if last command rc was false.

                  echo FALSE Since last rc was true, shouldn't it have stopped before this?
                  Nope. Instead, it skips the 'echo FALSE', does not even try to
                  execute it, and continues looking for a `&&` clause.

                  && ... which it finds here

                  echo TRUE ... so, since `[[ A == A ]]` is true, then it echos "TRUE"


                  The risk of logic errors when using more than one && or || in a command list is quite high.



                  Recommendations



                  A single && or || in a command list works as expected so is pretty safe. If it's a situation where you don't need an else clause, something like the following can be clearer to follow (the curly braces are required to group the last 2 commands) ...



                  [[ $1 == --help ]]  && { echo "$HELP"; exit; }


                  Multiple && and || operators, where each command except for the last is a test (i.e. inside brackets [[ ]]), are usually also safe as all but the last operator behave as expected. The last operator acts more like a then or else clause.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Mar 7 '17 at 9:15

























                  answered Sep 6 '13 at 10:35









                  DocSalvagerDocSalvager

                  1,32021732




                  1,32021732























                      0














                      I also got confused by this but here's how I think about the way Bash reads your statement (as it reads the symbols left to right):




                      1. Found symbol true. This will need to be evaluated once the end of the command is reached. At this point, don't know if it has any arguments. Store command in execution buffer.

                      2. Found symbol ||. Previous command is now complete, so evaluate it. Command (buffer) being executed: true. Result of evaluation: 0 (i.e. success). Store result 0 in "last evaluation" register. Now consider symbol || itself. This depends on the result of the last evaluation being non-zero. Checked "last evaluation" register and found 0. Since 0 is not non-zero, the following command does not need to be evaluated.

                      3. Found symbol echo. Can ignore this symbol, because the following command did not need to be evaluated.

                      4. Found symbol aaa. This is an argument to command echo (3), but since echo (3) did not need to be evaluated, it can be ignored.

                      5. Found symbol &&. This depends on the result of the last evaluation being zero. Checked "last evaluation" register and found 0. Since 0 is zero, the following command does need to be evaluated.

                      6. Found symbol echo. This command needs to be evaluated once the end of the command is reached, because the following command did need to be evaluated. Store command in execution buffer.

                      7. Found symbol bbb. This is an argument to command echo (6). Since echo did need to be evaluated, add bbb to execution buffer.

                      8. Reached end of line. Previous command is now complete and did need to be evaluated. Command (buffer) being executed: echo bbb. Result of evaluation: 0 (i.e. success). Store result 0 in "last evaluation" register.


                      And of course, the last step causes bbb to be echoed to the console.






                      share|improve this answer




























                        0














                        I also got confused by this but here's how I think about the way Bash reads your statement (as it reads the symbols left to right):




                        1. Found symbol true. This will need to be evaluated once the end of the command is reached. At this point, don't know if it has any arguments. Store command in execution buffer.

                        2. Found symbol ||. Previous command is now complete, so evaluate it. Command (buffer) being executed: true. Result of evaluation: 0 (i.e. success). Store result 0 in "last evaluation" register. Now consider symbol || itself. This depends on the result of the last evaluation being non-zero. Checked "last evaluation" register and found 0. Since 0 is not non-zero, the following command does not need to be evaluated.

                        3. Found symbol echo. Can ignore this symbol, because the following command did not need to be evaluated.

                        4. Found symbol aaa. This is an argument to command echo (3), but since echo (3) did not need to be evaluated, it can be ignored.

                        5. Found symbol &&. This depends on the result of the last evaluation being zero. Checked "last evaluation" register and found 0. Since 0 is zero, the following command does need to be evaluated.

                        6. Found symbol echo. This command needs to be evaluated once the end of the command is reached, because the following command did need to be evaluated. Store command in execution buffer.

                        7. Found symbol bbb. This is an argument to command echo (6). Since echo did need to be evaluated, add bbb to execution buffer.

                        8. Reached end of line. Previous command is now complete and did need to be evaluated. Command (buffer) being executed: echo bbb. Result of evaluation: 0 (i.e. success). Store result 0 in "last evaluation" register.


                        And of course, the last step causes bbb to be echoed to the console.






                        share|improve this answer


























                          0












                          0








                          0







                          I also got confused by this but here's how I think about the way Bash reads your statement (as it reads the symbols left to right):




                          1. Found symbol true. This will need to be evaluated once the end of the command is reached. At this point, don't know if it has any arguments. Store command in execution buffer.

                          2. Found symbol ||. Previous command is now complete, so evaluate it. Command (buffer) being executed: true. Result of evaluation: 0 (i.e. success). Store result 0 in "last evaluation" register. Now consider symbol || itself. This depends on the result of the last evaluation being non-zero. Checked "last evaluation" register and found 0. Since 0 is not non-zero, the following command does not need to be evaluated.

                          3. Found symbol echo. Can ignore this symbol, because the following command did not need to be evaluated.

                          4. Found symbol aaa. This is an argument to command echo (3), but since echo (3) did not need to be evaluated, it can be ignored.

                          5. Found symbol &&. This depends on the result of the last evaluation being zero. Checked "last evaluation" register and found 0. Since 0 is zero, the following command does need to be evaluated.

                          6. Found symbol echo. This command needs to be evaluated once the end of the command is reached, because the following command did need to be evaluated. Store command in execution buffer.

                          7. Found symbol bbb. This is an argument to command echo (6). Since echo did need to be evaluated, add bbb to execution buffer.

                          8. Reached end of line. Previous command is now complete and did need to be evaluated. Command (buffer) being executed: echo bbb. Result of evaluation: 0 (i.e. success). Store result 0 in "last evaluation" register.


                          And of course, the last step causes bbb to be echoed to the console.






                          share|improve this answer













                          I also got confused by this but here's how I think about the way Bash reads your statement (as it reads the symbols left to right):




                          1. Found symbol true. This will need to be evaluated once the end of the command is reached. At this point, don't know if it has any arguments. Store command in execution buffer.

                          2. Found symbol ||. Previous command is now complete, so evaluate it. Command (buffer) being executed: true. Result of evaluation: 0 (i.e. success). Store result 0 in "last evaluation" register. Now consider symbol || itself. This depends on the result of the last evaluation being non-zero. Checked "last evaluation" register and found 0. Since 0 is not non-zero, the following command does not need to be evaluated.

                          3. Found symbol echo. Can ignore this symbol, because the following command did not need to be evaluated.

                          4. Found symbol aaa. This is an argument to command echo (3), but since echo (3) did not need to be evaluated, it can be ignored.

                          5. Found symbol &&. This depends on the result of the last evaluation being zero. Checked "last evaluation" register and found 0. Since 0 is zero, the following command does need to be evaluated.

                          6. Found symbol echo. This command needs to be evaluated once the end of the command is reached, because the following command did need to be evaluated. Store command in execution buffer.

                          7. Found symbol bbb. This is an argument to command echo (6). Since echo did need to be evaluated, add bbb to execution buffer.

                          8. Reached end of line. Previous command is now complete and did need to be evaluated. Command (buffer) being executed: echo bbb. Result of evaluation: 0 (i.e. success). Store result 0 in "last evaluation" register.


                          And of course, the last step causes bbb to be echoed to the console.







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Jan 25 '18 at 20:00









                          KidburlaKidburla

                          5531313




                          5531313






























                              draft saved

                              draft discarded




















































                              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.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f88850%2fprecedence-of-the-shell-logical-operators%23new-answer', 'question_page');
                              }
                              );

                              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







                              Popular posts from this blog

                              CARDNET

                              Boot-repair Failure: Unable to locate package grub-common:i386

                              Aws NAT - Aws IGW- Aws router