Bash block and return codes — need explanation












0















I've been using Bash for a long time, but it seems I still miss something. Please consider this code:



function surprise {
true && {
echo 'Expected';
false;
} || {
echo 'Unexpected';
}
}

surprise;


which is shortened demonstration of my real problem and the output:



Expected
Unexpected


Till now I have thought, that whatever "Expected" block returns does not affect || in front of the "Unexpected" block, but it seems, like || is not checked against the output of true command, but in fact of the false command inside brackets.



Can someone, please, explain, what actually just happened? Thank you in advance.










share|improve this question



























    0















    I've been using Bash for a long time, but it seems I still miss something. Please consider this code:



    function surprise {
    true && {
    echo 'Expected';
    false;
    } || {
    echo 'Unexpected';
    }
    }

    surprise;


    which is shortened demonstration of my real problem and the output:



    Expected
    Unexpected


    Till now I have thought, that whatever "Expected" block returns does not affect || in front of the "Unexpected" block, but it seems, like || is not checked against the output of true command, but in fact of the false command inside brackets.



    Can someone, please, explain, what actually just happened? Thank you in advance.










    share|improve this question

























      0












      0








      0








      I've been using Bash for a long time, but it seems I still miss something. Please consider this code:



      function surprise {
      true && {
      echo 'Expected';
      false;
      } || {
      echo 'Unexpected';
      }
      }

      surprise;


      which is shortened demonstration of my real problem and the output:



      Expected
      Unexpected


      Till now I have thought, that whatever "Expected" block returns does not affect || in front of the "Unexpected" block, but it seems, like || is not checked against the output of true command, but in fact of the false command inside brackets.



      Can someone, please, explain, what actually just happened? Thank you in advance.










      share|improve this question














      I've been using Bash for a long time, but it seems I still miss something. Please consider this code:



      function surprise {
      true && {
      echo 'Expected';
      false;
      } || {
      echo 'Unexpected';
      }
      }

      surprise;


      which is shortened demonstration of my real problem and the output:



      Expected
      Unexpected


      Till now I have thought, that whatever "Expected" block returns does not affect || in front of the "Unexpected" block, but it seems, like || is not checked against the output of true command, but in fact of the false command inside brackets.



      Can someone, please, explain, what actually just happened? Thank you in advance.







      bash






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Jan 29 at 19:44









      CromaxCromax

      1034




      1034






















          3 Answers
          3






          active

          oldest

          votes


















          2















          it seems, like || is not checked against the output of true command, but in fact of the false command inside brackets.




          You could say that's the case.



          x && y || z is not an if/then/else structure, nor should be used as one. It is a combination of boolean operators – the equivalent of "x AND y OR z" – and will evaluate as many commands as it needs to in order to determine the result. (The evaluation is left-to-right unless grouped by parentheses or braces, just like in most programming languages, so the order is (x && y) || z.)



          So in order to determine the result of x && y, when x is true, y must also be evaluated. On the other hand, when x is false, the result will be false no matter what, so it'll just short-circuit and skip the evaluation of y.



          Whether the values in between are single commands or {cmd; cmd; cmd} blocks actually doesn't matter at all; in this situation it merely helps you see the actual effects.






          share|improve this answer


























          • The short-circuit... I really thought of && and || more like if-then-else, but now I get it--thanks!

            – Cromax
            Jan 29 at 20:12





















          2














          First: you can think of each of the "blocks" as just complex commands, not something significantly different. Thus, what you really have is just:



          cmd1 && cmd2 || cmd3


          ...and the fact that cmd2 and cmd3 are blocks rather than simple commands doesn't matter. Now, the important thing is that given that command sequence, the logical precedence of && and || "operators" makes it something like this:



          ( cmd1 && cmd2 ) || cmd3


          (Note: actually, those parentheses would force a subshell. I'm ignoring that.) If you look at the logical structure of that, it's ( something ) || cmd3, so clearly it's going to run cmd3 if something fails. But something is actually cmd1 && cmd2, which succeeds if *both cmd1 and cmd2 succeed -- which means it fails if either cmd1 or cmd2 fails.



          So, logically, that'll wind up running cmd3 if either cmd1 or cmd2 fails. In your actual code, cmd2 always fails, so cmd3 always runs.






          share|improve this answer































            0














            The double and (&&) and the double pipe (||) have meaning in process control in Linux.



            Think of them as logical operators.



            command1 && command2


            or



            command1 || command2


            Or



            command1 && command2 || command3


            Basically, in all 3 cases, command1 runs. If it has a NON-ZERO exit status (an error of some type) it is considered to not have successfully run.



            With the && - thinking of a logical AND in programming - there is no need to run the second command, because the first one failed in some way.



            With the || - thinking of a logical OR - the if the first is successful (exit 0) there is no need to check the second condition - only one or the other has to be successful.



            With the 3rd example, if command1 is successful, it will run command2. If it wasn't successful, it will instead run command3



            In your example, the || is detecting the exit status of your false command.






            share|improve this answer























              Your Answer








              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "3"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: true,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsuperuser.com%2fquestions%2f1399781%2fbash-block-and-return-codes-need-explanation%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              3 Answers
              3






              active

              oldest

              votes








              3 Answers
              3






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              2















              it seems, like || is not checked against the output of true command, but in fact of the false command inside brackets.




              You could say that's the case.



              x && y || z is not an if/then/else structure, nor should be used as one. It is a combination of boolean operators – the equivalent of "x AND y OR z" – and will evaluate as many commands as it needs to in order to determine the result. (The evaluation is left-to-right unless grouped by parentheses or braces, just like in most programming languages, so the order is (x && y) || z.)



              So in order to determine the result of x && y, when x is true, y must also be evaluated. On the other hand, when x is false, the result will be false no matter what, so it'll just short-circuit and skip the evaluation of y.



              Whether the values in between are single commands or {cmd; cmd; cmd} blocks actually doesn't matter at all; in this situation it merely helps you see the actual effects.






              share|improve this answer


























              • The short-circuit... I really thought of && and || more like if-then-else, but now I get it--thanks!

                – Cromax
                Jan 29 at 20:12


















              2















              it seems, like || is not checked against the output of true command, but in fact of the false command inside brackets.




              You could say that's the case.



              x && y || z is not an if/then/else structure, nor should be used as one. It is a combination of boolean operators – the equivalent of "x AND y OR z" – and will evaluate as many commands as it needs to in order to determine the result. (The evaluation is left-to-right unless grouped by parentheses or braces, just like in most programming languages, so the order is (x && y) || z.)



              So in order to determine the result of x && y, when x is true, y must also be evaluated. On the other hand, when x is false, the result will be false no matter what, so it'll just short-circuit and skip the evaluation of y.



              Whether the values in between are single commands or {cmd; cmd; cmd} blocks actually doesn't matter at all; in this situation it merely helps you see the actual effects.






              share|improve this answer


























              • The short-circuit... I really thought of && and || more like if-then-else, but now I get it--thanks!

                – Cromax
                Jan 29 at 20:12
















              2












              2








              2








              it seems, like || is not checked against the output of true command, but in fact of the false command inside brackets.




              You could say that's the case.



              x && y || z is not an if/then/else structure, nor should be used as one. It is a combination of boolean operators – the equivalent of "x AND y OR z" – and will evaluate as many commands as it needs to in order to determine the result. (The evaluation is left-to-right unless grouped by parentheses or braces, just like in most programming languages, so the order is (x && y) || z.)



              So in order to determine the result of x && y, when x is true, y must also be evaluated. On the other hand, when x is false, the result will be false no matter what, so it'll just short-circuit and skip the evaluation of y.



              Whether the values in between are single commands or {cmd; cmd; cmd} blocks actually doesn't matter at all; in this situation it merely helps you see the actual effects.






              share|improve this answer
















              it seems, like || is not checked against the output of true command, but in fact of the false command inside brackets.




              You could say that's the case.



              x && y || z is not an if/then/else structure, nor should be used as one. It is a combination of boolean operators – the equivalent of "x AND y OR z" – and will evaluate as many commands as it needs to in order to determine the result. (The evaluation is left-to-right unless grouped by parentheses or braces, just like in most programming languages, so the order is (x && y) || z.)



              So in order to determine the result of x && y, when x is true, y must also be evaluated. On the other hand, when x is false, the result will be false no matter what, so it'll just short-circuit and skip the evaluation of y.



              Whether the values in between are single commands or {cmd; cmd; cmd} blocks actually doesn't matter at all; in this situation it merely helps you see the actual effects.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Jan 29 at 20:20


























              community wiki





              2 revs
              grawity














              • The short-circuit... I really thought of && and || more like if-then-else, but now I get it--thanks!

                – Cromax
                Jan 29 at 20:12





















              • The short-circuit... I really thought of && and || more like if-then-else, but now I get it--thanks!

                – Cromax
                Jan 29 at 20:12



















              The short-circuit... I really thought of && and || more like if-then-else, but now I get it--thanks!

              – Cromax
              Jan 29 at 20:12







              The short-circuit... I really thought of && and || more like if-then-else, but now I get it--thanks!

              – Cromax
              Jan 29 at 20:12















              2














              First: you can think of each of the "blocks" as just complex commands, not something significantly different. Thus, what you really have is just:



              cmd1 && cmd2 || cmd3


              ...and the fact that cmd2 and cmd3 are blocks rather than simple commands doesn't matter. Now, the important thing is that given that command sequence, the logical precedence of && and || "operators" makes it something like this:



              ( cmd1 && cmd2 ) || cmd3


              (Note: actually, those parentheses would force a subshell. I'm ignoring that.) If you look at the logical structure of that, it's ( something ) || cmd3, so clearly it's going to run cmd3 if something fails. But something is actually cmd1 && cmd2, which succeeds if *both cmd1 and cmd2 succeed -- which means it fails if either cmd1 or cmd2 fails.



              So, logically, that'll wind up running cmd3 if either cmd1 or cmd2 fails. In your actual code, cmd2 always fails, so cmd3 always runs.






              share|improve this answer




























                2














                First: you can think of each of the "blocks" as just complex commands, not something significantly different. Thus, what you really have is just:



                cmd1 && cmd2 || cmd3


                ...and the fact that cmd2 and cmd3 are blocks rather than simple commands doesn't matter. Now, the important thing is that given that command sequence, the logical precedence of && and || "operators" makes it something like this:



                ( cmd1 && cmd2 ) || cmd3


                (Note: actually, those parentheses would force a subshell. I'm ignoring that.) If you look at the logical structure of that, it's ( something ) || cmd3, so clearly it's going to run cmd3 if something fails. But something is actually cmd1 && cmd2, which succeeds if *both cmd1 and cmd2 succeed -- which means it fails if either cmd1 or cmd2 fails.



                So, logically, that'll wind up running cmd3 if either cmd1 or cmd2 fails. In your actual code, cmd2 always fails, so cmd3 always runs.






                share|improve this answer


























                  2












                  2








                  2







                  First: you can think of each of the "blocks" as just complex commands, not something significantly different. Thus, what you really have is just:



                  cmd1 && cmd2 || cmd3


                  ...and the fact that cmd2 and cmd3 are blocks rather than simple commands doesn't matter. Now, the important thing is that given that command sequence, the logical precedence of && and || "operators" makes it something like this:



                  ( cmd1 && cmd2 ) || cmd3


                  (Note: actually, those parentheses would force a subshell. I'm ignoring that.) If you look at the logical structure of that, it's ( something ) || cmd3, so clearly it's going to run cmd3 if something fails. But something is actually cmd1 && cmd2, which succeeds if *both cmd1 and cmd2 succeed -- which means it fails if either cmd1 or cmd2 fails.



                  So, logically, that'll wind up running cmd3 if either cmd1 or cmd2 fails. In your actual code, cmd2 always fails, so cmd3 always runs.






                  share|improve this answer













                  First: you can think of each of the "blocks" as just complex commands, not something significantly different. Thus, what you really have is just:



                  cmd1 && cmd2 || cmd3


                  ...and the fact that cmd2 and cmd3 are blocks rather than simple commands doesn't matter. Now, the important thing is that given that command sequence, the logical precedence of && and || "operators" makes it something like this:



                  ( cmd1 && cmd2 ) || cmd3


                  (Note: actually, those parentheses would force a subshell. I'm ignoring that.) If you look at the logical structure of that, it's ( something ) || cmd3, so clearly it's going to run cmd3 if something fails. But something is actually cmd1 && cmd2, which succeeds if *both cmd1 and cmd2 succeed -- which means it fails if either cmd1 or cmd2 fails.



                  So, logically, that'll wind up running cmd3 if either cmd1 or cmd2 fails. In your actual code, cmd2 always fails, so cmd3 always runs.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Jan 29 at 20:06









                  Gordon DavissonGordon Davisson

                  26k44350




                  26k44350























                      0














                      The double and (&&) and the double pipe (||) have meaning in process control in Linux.



                      Think of them as logical operators.



                      command1 && command2


                      or



                      command1 || command2


                      Or



                      command1 && command2 || command3


                      Basically, in all 3 cases, command1 runs. If it has a NON-ZERO exit status (an error of some type) it is considered to not have successfully run.



                      With the && - thinking of a logical AND in programming - there is no need to run the second command, because the first one failed in some way.



                      With the || - thinking of a logical OR - the if the first is successful (exit 0) there is no need to check the second condition - only one or the other has to be successful.



                      With the 3rd example, if command1 is successful, it will run command2. If it wasn't successful, it will instead run command3



                      In your example, the || is detecting the exit status of your false command.






                      share|improve this answer




























                        0














                        The double and (&&) and the double pipe (||) have meaning in process control in Linux.



                        Think of them as logical operators.



                        command1 && command2


                        or



                        command1 || command2


                        Or



                        command1 && command2 || command3


                        Basically, in all 3 cases, command1 runs. If it has a NON-ZERO exit status (an error of some type) it is considered to not have successfully run.



                        With the && - thinking of a logical AND in programming - there is no need to run the second command, because the first one failed in some way.



                        With the || - thinking of a logical OR - the if the first is successful (exit 0) there is no need to check the second condition - only one or the other has to be successful.



                        With the 3rd example, if command1 is successful, it will run command2. If it wasn't successful, it will instead run command3



                        In your example, the || is detecting the exit status of your false command.






                        share|improve this answer


























                          0












                          0








                          0







                          The double and (&&) and the double pipe (||) have meaning in process control in Linux.



                          Think of them as logical operators.



                          command1 && command2


                          or



                          command1 || command2


                          Or



                          command1 && command2 || command3


                          Basically, in all 3 cases, command1 runs. If it has a NON-ZERO exit status (an error of some type) it is considered to not have successfully run.



                          With the && - thinking of a logical AND in programming - there is no need to run the second command, because the first one failed in some way.



                          With the || - thinking of a logical OR - the if the first is successful (exit 0) there is no need to check the second condition - only one or the other has to be successful.



                          With the 3rd example, if command1 is successful, it will run command2. If it wasn't successful, it will instead run command3



                          In your example, the || is detecting the exit status of your false command.






                          share|improve this answer













                          The double and (&&) and the double pipe (||) have meaning in process control in Linux.



                          Think of them as logical operators.



                          command1 && command2


                          or



                          command1 || command2


                          Or



                          command1 && command2 || command3


                          Basically, in all 3 cases, command1 runs. If it has a NON-ZERO exit status (an error of some type) it is considered to not have successfully run.



                          With the && - thinking of a logical AND in programming - there is no need to run the second command, because the first one failed in some way.



                          With the || - thinking of a logical OR - the if the first is successful (exit 0) there is no need to check the second condition - only one or the other has to be successful.



                          With the 3rd example, if command1 is successful, it will run command2. If it wasn't successful, it will instead run command3



                          In your example, the || is detecting the exit status of your false command.







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Jan 29 at 20:02









                          ivanivanivanivan

                          1,25427




                          1,25427






























                              draft saved

                              draft discarded




















































                              Thanks for contributing an answer to Super User!


                              • 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%2fsuperuser.com%2fquestions%2f1399781%2fbash-block-and-return-codes-need-explanation%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

                              How to reconfigure Docker Trusted Registry 2.x.x to use CEPH FS mount instead of NFS and other traditional...

                              is 'sed' thread safe

                              How to make a Squid Proxy server?