“foo && bar || baz” in bash behaving differently from “if foo; then bar; else baz” [duplicate]

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
5
down vote

favorite













This question already has an answer here:



  • Precedence of the shell logical operators &&, ||

    4 answers



I thought



[ 1 -eq $1 ] && echo "yes" || echo "no"


Acts like



if [ 1 -eq $1 ]; then
echo "yes"
else
echo "no"
fi


But, when I run this script (nocmd is a non-existing command)



#!/bin/bash

[ 1 -eq $1 ] && nocmd "yes" || echo "no"


I get a strange output for parameter '1':



me@ubuntu:/tmp$ ./ddd.sh 0
no
me@ubuntu:/tmp$ ./ddd.sh 1
./sh.sh: line 3: nocmd: command not found
no


Looks like it acts like:



if [ 1 -eq $1 ]; then
nocmd "yes"
if [ $? -ne 0 ]; then
echo "no"
fi
else
echo "no"
fi


Is it fine? Am I missing something?







share|improve this question














marked as duplicate by G-Man, muru, Jakuje, αғsнιη, Hunter.S.Thompson Jan 31 at 10:59


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.










  • 4




    It's no strange thing there, when you ran with ./ddd.sh 0 this part will check [ 1 -eq $1 ] it's not true (false) (1!=0), so this part won't run && nocmd "yes" and this part will run || echo "no", but when it's true 1=1 it will execute && nocmd "yes" part and since shell doesn't recognize nocmd command, it's reported error .... command not found and again second part will run || echo "no".
    – Î±Ò“sнιη
    Jan 30 at 17:00















up vote
5
down vote

favorite













This question already has an answer here:



  • Precedence of the shell logical operators &&, ||

    4 answers



I thought



[ 1 -eq $1 ] && echo "yes" || echo "no"


Acts like



if [ 1 -eq $1 ]; then
echo "yes"
else
echo "no"
fi


But, when I run this script (nocmd is a non-existing command)



#!/bin/bash

[ 1 -eq $1 ] && nocmd "yes" || echo "no"


I get a strange output for parameter '1':



me@ubuntu:/tmp$ ./ddd.sh 0
no
me@ubuntu:/tmp$ ./ddd.sh 1
./sh.sh: line 3: nocmd: command not found
no


Looks like it acts like:



if [ 1 -eq $1 ]; then
nocmd "yes"
if [ $? -ne 0 ]; then
echo "no"
fi
else
echo "no"
fi


Is it fine? Am I missing something?







share|improve this question














marked as duplicate by G-Man, muru, Jakuje, αғsнιη, Hunter.S.Thompson Jan 31 at 10:59


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.










  • 4




    It's no strange thing there, when you ran with ./ddd.sh 0 this part will check [ 1 -eq $1 ] it's not true (false) (1!=0), so this part won't run && nocmd "yes" and this part will run || echo "no", but when it's true 1=1 it will execute && nocmd "yes" part and since shell doesn't recognize nocmd command, it's reported error .... command not found and again second part will run || echo "no".
    – Î±Ò“sнιη
    Jan 30 at 17:00













up vote
5
down vote

favorite









up vote
5
down vote

favorite












This question already has an answer here:



  • Precedence of the shell logical operators &&, ||

    4 answers



I thought



[ 1 -eq $1 ] && echo "yes" || echo "no"


Acts like



if [ 1 -eq $1 ]; then
echo "yes"
else
echo "no"
fi


But, when I run this script (nocmd is a non-existing command)



#!/bin/bash

[ 1 -eq $1 ] && nocmd "yes" || echo "no"


I get a strange output for parameter '1':



me@ubuntu:/tmp$ ./ddd.sh 0
no
me@ubuntu:/tmp$ ./ddd.sh 1
./sh.sh: line 3: nocmd: command not found
no


Looks like it acts like:



if [ 1 -eq $1 ]; then
nocmd "yes"
if [ $? -ne 0 ]; then
echo "no"
fi
else
echo "no"
fi


Is it fine? Am I missing something?







share|improve this question















This question already has an answer here:



  • Precedence of the shell logical operators &&, ||

    4 answers



I thought



[ 1 -eq $1 ] && echo "yes" || echo "no"


Acts like



if [ 1 -eq $1 ]; then
echo "yes"
else
echo "no"
fi


But, when I run this script (nocmd is a non-existing command)



#!/bin/bash

[ 1 -eq $1 ] && nocmd "yes" || echo "no"


I get a strange output for parameter '1':



me@ubuntu:/tmp$ ./ddd.sh 0
no
me@ubuntu:/tmp$ ./ddd.sh 1
./sh.sh: line 3: nocmd: command not found
no


Looks like it acts like:



if [ 1 -eq $1 ]; then
nocmd "yes"
if [ $? -ne 0 ]; then
echo "no"
fi
else
echo "no"
fi


Is it fine? Am I missing something?





This question already has an answer here:



  • Precedence of the shell logical operators &&, ||

    4 answers









share|improve this question













share|improve this question




share|improve this question








edited Jan 30 at 21:52









Charles Duffy

736413




736413










asked Jan 30 at 16:55









hudac

327312




327312




marked as duplicate by G-Man, muru, Jakuje, αғsнιη, Hunter.S.Thompson Jan 31 at 10:59


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.






marked as duplicate by G-Man, muru, Jakuje, αғsнιη, Hunter.S.Thompson Jan 31 at 10:59


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.









  • 4




    It's no strange thing there, when you ran with ./ddd.sh 0 this part will check [ 1 -eq $1 ] it's not true (false) (1!=0), so this part won't run && nocmd "yes" and this part will run || echo "no", but when it's true 1=1 it will execute && nocmd "yes" part and since shell doesn't recognize nocmd command, it's reported error .... command not found and again second part will run || echo "no".
    – Î±Ò“sнιη
    Jan 30 at 17:00













  • 4




    It's no strange thing there, when you ran with ./ddd.sh 0 this part will check [ 1 -eq $1 ] it's not true (false) (1!=0), so this part won't run && nocmd "yes" and this part will run || echo "no", but when it's true 1=1 it will execute && nocmd "yes" part and since shell doesn't recognize nocmd command, it's reported error .... command not found and again second part will run || echo "no".
    – Î±Ò“sнιη
    Jan 30 at 17:00








4




4




It's no strange thing there, when you ran with ./ddd.sh 0 this part will check [ 1 -eq $1 ] it's not true (false) (1!=0), so this part won't run && nocmd "yes" and this part will run || echo "no", but when it's true 1=1 it will execute && nocmd "yes" part and since shell doesn't recognize nocmd command, it's reported error .... command not found and again second part will run || echo "no".
– Î±Ò“sнιη
Jan 30 at 17:00





It's no strange thing there, when you ran with ./ddd.sh 0 this part will check [ 1 -eq $1 ] it's not true (false) (1!=0), so this part won't run && nocmd "yes" and this part will run || echo "no", but when it's true 1=1 it will execute && nocmd "yes" part and since shell doesn't recognize nocmd command, it's reported error .... command not found and again second part will run || echo "no".
– Î±Ò“sнιη
Jan 30 at 17:00











3 Answers
3






active

oldest

votes

















up vote
19
down vote



accepted










Except for the overall exit status, it acts like:



if
!
[ 1 -eq $1 ] && nocmd "yes"

then
echo no
fi


In:



A || B


B is executed iff A fails. That's a OR operator.



In your case A is [ 1 -eq $1 ] && nocmd "yes" where nocmd is run iff [ succeeds (a AND operator), in which case the exit status of A will be that of nocmd. In other words echo no will be executed if either [ or nocmd "yes" fails (bearing in mind that nocmd is only run if [ succeeds).



Those x && y || z are dirty hacks. They are best avoided for that very reason. Use a if/then/else construct if you do want a if/then/else logic. Use x && y || z only if you want z to be unless both x and y succeeded.



Even in:



cmd && echo OK || echo >&2 KO


The echo OK could fail under some pathological conditions (like stdout going to a file on a full filesystem), and echo >&2 KO could end up being executed as well.



$ bash -c 'true && echo OK || echo KO >&2' > /dev/full
bash: line 0: echo: write error: No space left on device
KO





share|improve this answer





























    up vote
    5
    down vote













    Well, what actually happens is this (and this is how && and || works)



    test 1 -eq $1
    ret=$?
    if [ $ret -eq 0 ]; then
    nocmd "yes"
    ret=$?
    fi
    if [ $ret -ne 0 ]; then
    echo "no"
    fi


    In your case, if $1 does not equal 1, or is not a valid number, then you have a non-zero $?, and the first if is skipped, and the second if prints "no". If $1 equals 1 , then nocmd "yes" is executed, returning a non-zero $?, and "no" is also echoed.






    share|improve this answer






















    • That's not exactly true, and the reason is a bit weird. An if statement returns 0 if it doesn't run either of the then and else branches. So if the first test fails, $? is zero on the second test, always. if false ; then echo x; fi; echo $? prints 0.
      – ilkkachu
      Jan 30 at 17:40










    • @ilkkachu Noted. I didn't know that before.
      – Weijun Zhou
      Jan 30 at 17:41










    • It's really more like that, at least I get the same result for that construct and the && .. || chain
      – ilkkachu
      Jan 30 at 17:43










    • @ilkkachu So you mean that my original version of code is valid but for more complicated reasons?
      – Weijun Zhou
      Jan 30 at 17:45






    • 1




      no, with the test directly against $?, the double-if gives a different result from the && ||, since the first if-statement throws the second off. With the temporary variable the behavior matches. See: pastebin.com/q0Ct0Zw8 for the difference without the temp
      – ilkkachu
      Jan 30 at 17:56

















    up vote
    3
    down vote













    What you're missing is that && and || operate on exit status of commands to the left of them - left associativity. You have here some group of commands || echo "no", and no will be echoed if and only if that group of commands returns non-success exit status.



    What is that group of commands ? In first case you have [ 1 -eq "$1" ] && echo "yes". If [ portion failed, that'd be counted as fail exit status for [ 1 -eq "$1" ] && echo "yes", therefore you'd echo "no" would run. Also because of left associativity, when "$1" is 1, the [ 1 -eq $1 ] returns success, then lets nocmd run which doesn't exist and shell will return error exit status, the whole group will have exit status of fail, hence `"no" is echoed.



    By contrast, in your if statement



    if [ 1 -eq $1 ]; then
    echo "yes"
    else
    echo "no"
    fi


    which route to take depends only on exit status of [ portion. In [ 1 -eq "$1" ] && echo "Yes" || echo "no" echo also plays role as to whether or not echo "no" runs.



    Your second if statement example is also different



    if [ 1 -eq $1 ]; then
    nocmd "yes"
    if [ $? -ne 0 ]; then
    echo "no"
    fi
    else
    echo "no"
    fi


    The echo "no" after else doesn't depend on what happens to nocmd as in the chaining of logical operators. Sure you still do the echo "no" part after doing nocmd, but here its exit status isn't grouped together with the whole if portion to which it belongs.






    share|improve this answer





























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      19
      down vote



      accepted










      Except for the overall exit status, it acts like:



      if
      !
      [ 1 -eq $1 ] && nocmd "yes"

      then
      echo no
      fi


      In:



      A || B


      B is executed iff A fails. That's a OR operator.



      In your case A is [ 1 -eq $1 ] && nocmd "yes" where nocmd is run iff [ succeeds (a AND operator), in which case the exit status of A will be that of nocmd. In other words echo no will be executed if either [ or nocmd "yes" fails (bearing in mind that nocmd is only run if [ succeeds).



      Those x && y || z are dirty hacks. They are best avoided for that very reason. Use a if/then/else construct if you do want a if/then/else logic. Use x && y || z only if you want z to be unless both x and y succeeded.



      Even in:



      cmd && echo OK || echo >&2 KO


      The echo OK could fail under some pathological conditions (like stdout going to a file on a full filesystem), and echo >&2 KO could end up being executed as well.



      $ bash -c 'true && echo OK || echo KO >&2' > /dev/full
      bash: line 0: echo: write error: No space left on device
      KO





      share|improve this answer


























        up vote
        19
        down vote



        accepted










        Except for the overall exit status, it acts like:



        if
        !
        [ 1 -eq $1 ] && nocmd "yes"

        then
        echo no
        fi


        In:



        A || B


        B is executed iff A fails. That's a OR operator.



        In your case A is [ 1 -eq $1 ] && nocmd "yes" where nocmd is run iff [ succeeds (a AND operator), in which case the exit status of A will be that of nocmd. In other words echo no will be executed if either [ or nocmd "yes" fails (bearing in mind that nocmd is only run if [ succeeds).



        Those x && y || z are dirty hacks. They are best avoided for that very reason. Use a if/then/else construct if you do want a if/then/else logic. Use x && y || z only if you want z to be unless both x and y succeeded.



        Even in:



        cmd && echo OK || echo >&2 KO


        The echo OK could fail under some pathological conditions (like stdout going to a file on a full filesystem), and echo >&2 KO could end up being executed as well.



        $ bash -c 'true && echo OK || echo KO >&2' > /dev/full
        bash: line 0: echo: write error: No space left on device
        KO





        share|improve this answer
























          up vote
          19
          down vote



          accepted







          up vote
          19
          down vote



          accepted






          Except for the overall exit status, it acts like:



          if
          !
          [ 1 -eq $1 ] && nocmd "yes"

          then
          echo no
          fi


          In:



          A || B


          B is executed iff A fails. That's a OR operator.



          In your case A is [ 1 -eq $1 ] && nocmd "yes" where nocmd is run iff [ succeeds (a AND operator), in which case the exit status of A will be that of nocmd. In other words echo no will be executed if either [ or nocmd "yes" fails (bearing in mind that nocmd is only run if [ succeeds).



          Those x && y || z are dirty hacks. They are best avoided for that very reason. Use a if/then/else construct if you do want a if/then/else logic. Use x && y || z only if you want z to be unless both x and y succeeded.



          Even in:



          cmd && echo OK || echo >&2 KO


          The echo OK could fail under some pathological conditions (like stdout going to a file on a full filesystem), and echo >&2 KO could end up being executed as well.



          $ bash -c 'true && echo OK || echo KO >&2' > /dev/full
          bash: line 0: echo: write error: No space left on device
          KO





          share|improve this answer














          Except for the overall exit status, it acts like:



          if
          !
          [ 1 -eq $1 ] && nocmd "yes"

          then
          echo no
          fi


          In:



          A || B


          B is executed iff A fails. That's a OR operator.



          In your case A is [ 1 -eq $1 ] && nocmd "yes" where nocmd is run iff [ succeeds (a AND operator), in which case the exit status of A will be that of nocmd. In other words echo no will be executed if either [ or nocmd "yes" fails (bearing in mind that nocmd is only run if [ succeeds).



          Those x && y || z are dirty hacks. They are best avoided for that very reason. Use a if/then/else construct if you do want a if/then/else logic. Use x && y || z only if you want z to be unless both x and y succeeded.



          Even in:



          cmd && echo OK || echo >&2 KO


          The echo OK could fail under some pathological conditions (like stdout going to a file on a full filesystem), and echo >&2 KO could end up being executed as well.



          $ bash -c 'true && echo OK || echo KO >&2' > /dev/full
          bash: line 0: echo: write error: No space left on device
          KO






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jan 30 at 17:22

























          answered Jan 30 at 17:01









          Stéphane Chazelas

          281k53516847




          281k53516847






















              up vote
              5
              down vote













              Well, what actually happens is this (and this is how && and || works)



              test 1 -eq $1
              ret=$?
              if [ $ret -eq 0 ]; then
              nocmd "yes"
              ret=$?
              fi
              if [ $ret -ne 0 ]; then
              echo "no"
              fi


              In your case, if $1 does not equal 1, or is not a valid number, then you have a non-zero $?, and the first if is skipped, and the second if prints "no". If $1 equals 1 , then nocmd "yes" is executed, returning a non-zero $?, and "no" is also echoed.






              share|improve this answer






















              • That's not exactly true, and the reason is a bit weird. An if statement returns 0 if it doesn't run either of the then and else branches. So if the first test fails, $? is zero on the second test, always. if false ; then echo x; fi; echo $? prints 0.
                – ilkkachu
                Jan 30 at 17:40










              • @ilkkachu Noted. I didn't know that before.
                – Weijun Zhou
                Jan 30 at 17:41










              • It's really more like that, at least I get the same result for that construct and the && .. || chain
                – ilkkachu
                Jan 30 at 17:43










              • @ilkkachu So you mean that my original version of code is valid but for more complicated reasons?
                – Weijun Zhou
                Jan 30 at 17:45






              • 1




                no, with the test directly against $?, the double-if gives a different result from the && ||, since the first if-statement throws the second off. With the temporary variable the behavior matches. See: pastebin.com/q0Ct0Zw8 for the difference without the temp
                – ilkkachu
                Jan 30 at 17:56














              up vote
              5
              down vote













              Well, what actually happens is this (and this is how && and || works)



              test 1 -eq $1
              ret=$?
              if [ $ret -eq 0 ]; then
              nocmd "yes"
              ret=$?
              fi
              if [ $ret -ne 0 ]; then
              echo "no"
              fi


              In your case, if $1 does not equal 1, or is not a valid number, then you have a non-zero $?, and the first if is skipped, and the second if prints "no". If $1 equals 1 , then nocmd "yes" is executed, returning a non-zero $?, and "no" is also echoed.






              share|improve this answer






















              • That's not exactly true, and the reason is a bit weird. An if statement returns 0 if it doesn't run either of the then and else branches. So if the first test fails, $? is zero on the second test, always. if false ; then echo x; fi; echo $? prints 0.
                – ilkkachu
                Jan 30 at 17:40










              • @ilkkachu Noted. I didn't know that before.
                – Weijun Zhou
                Jan 30 at 17:41










              • It's really more like that, at least I get the same result for that construct and the && .. || chain
                – ilkkachu
                Jan 30 at 17:43










              • @ilkkachu So you mean that my original version of code is valid but for more complicated reasons?
                – Weijun Zhou
                Jan 30 at 17:45






              • 1




                no, with the test directly against $?, the double-if gives a different result from the && ||, since the first if-statement throws the second off. With the temporary variable the behavior matches. See: pastebin.com/q0Ct0Zw8 for the difference without the temp
                – ilkkachu
                Jan 30 at 17:56












              up vote
              5
              down vote










              up vote
              5
              down vote









              Well, what actually happens is this (and this is how && and || works)



              test 1 -eq $1
              ret=$?
              if [ $ret -eq 0 ]; then
              nocmd "yes"
              ret=$?
              fi
              if [ $ret -ne 0 ]; then
              echo "no"
              fi


              In your case, if $1 does not equal 1, or is not a valid number, then you have a non-zero $?, and the first if is skipped, and the second if prints "no". If $1 equals 1 , then nocmd "yes" is executed, returning a non-zero $?, and "no" is also echoed.






              share|improve this answer














              Well, what actually happens is this (and this is how && and || works)



              test 1 -eq $1
              ret=$?
              if [ $ret -eq 0 ]; then
              nocmd "yes"
              ret=$?
              fi
              if [ $ret -ne 0 ]; then
              echo "no"
              fi


              In your case, if $1 does not equal 1, or is not a valid number, then you have a non-zero $?, and the first if is skipped, and the second if prints "no". If $1 equals 1 , then nocmd "yes" is executed, returning a non-zero $?, and "no" is also echoed.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Jan 30 at 17:42









              ilkkachu

              49.8k674137




              49.8k674137










              answered Jan 30 at 17:01









              Weijun Zhou

              1,434119




              1,434119











              • That's not exactly true, and the reason is a bit weird. An if statement returns 0 if it doesn't run either of the then and else branches. So if the first test fails, $? is zero on the second test, always. if false ; then echo x; fi; echo $? prints 0.
                – ilkkachu
                Jan 30 at 17:40










              • @ilkkachu Noted. I didn't know that before.
                – Weijun Zhou
                Jan 30 at 17:41










              • It's really more like that, at least I get the same result for that construct and the && .. || chain
                – ilkkachu
                Jan 30 at 17:43










              • @ilkkachu So you mean that my original version of code is valid but for more complicated reasons?
                – Weijun Zhou
                Jan 30 at 17:45






              • 1




                no, with the test directly against $?, the double-if gives a different result from the && ||, since the first if-statement throws the second off. With the temporary variable the behavior matches. See: pastebin.com/q0Ct0Zw8 for the difference without the temp
                – ilkkachu
                Jan 30 at 17:56
















              • That's not exactly true, and the reason is a bit weird. An if statement returns 0 if it doesn't run either of the then and else branches. So if the first test fails, $? is zero on the second test, always. if false ; then echo x; fi; echo $? prints 0.
                – ilkkachu
                Jan 30 at 17:40










              • @ilkkachu Noted. I didn't know that before.
                – Weijun Zhou
                Jan 30 at 17:41










              • It's really more like that, at least I get the same result for that construct and the && .. || chain
                – ilkkachu
                Jan 30 at 17:43










              • @ilkkachu So you mean that my original version of code is valid but for more complicated reasons?
                – Weijun Zhou
                Jan 30 at 17:45






              • 1




                no, with the test directly against $?, the double-if gives a different result from the && ||, since the first if-statement throws the second off. With the temporary variable the behavior matches. See: pastebin.com/q0Ct0Zw8 for the difference without the temp
                – ilkkachu
                Jan 30 at 17:56















              That's not exactly true, and the reason is a bit weird. An if statement returns 0 if it doesn't run either of the then and else branches. So if the first test fails, $? is zero on the second test, always. if false ; then echo x; fi; echo $? prints 0.
              – ilkkachu
              Jan 30 at 17:40




              That's not exactly true, and the reason is a bit weird. An if statement returns 0 if it doesn't run either of the then and else branches. So if the first test fails, $? is zero on the second test, always. if false ; then echo x; fi; echo $? prints 0.
              – ilkkachu
              Jan 30 at 17:40












              @ilkkachu Noted. I didn't know that before.
              – Weijun Zhou
              Jan 30 at 17:41




              @ilkkachu Noted. I didn't know that before.
              – Weijun Zhou
              Jan 30 at 17:41












              It's really more like that, at least I get the same result for that construct and the && .. || chain
              – ilkkachu
              Jan 30 at 17:43




              It's really more like that, at least I get the same result for that construct and the && .. || chain
              – ilkkachu
              Jan 30 at 17:43












              @ilkkachu So you mean that my original version of code is valid but for more complicated reasons?
              – Weijun Zhou
              Jan 30 at 17:45




              @ilkkachu So you mean that my original version of code is valid but for more complicated reasons?
              – Weijun Zhou
              Jan 30 at 17:45




              1




              1




              no, with the test directly against $?, the double-if gives a different result from the && ||, since the first if-statement throws the second off. With the temporary variable the behavior matches. See: pastebin.com/q0Ct0Zw8 for the difference without the temp
              – ilkkachu
              Jan 30 at 17:56




              no, with the test directly against $?, the double-if gives a different result from the && ||, since the first if-statement throws the second off. With the temporary variable the behavior matches. See: pastebin.com/q0Ct0Zw8 for the difference without the temp
              – ilkkachu
              Jan 30 at 17:56










              up vote
              3
              down vote













              What you're missing is that && and || operate on exit status of commands to the left of them - left associativity. You have here some group of commands || echo "no", and no will be echoed if and only if that group of commands returns non-success exit status.



              What is that group of commands ? In first case you have [ 1 -eq "$1" ] && echo "yes". If [ portion failed, that'd be counted as fail exit status for [ 1 -eq "$1" ] && echo "yes", therefore you'd echo "no" would run. Also because of left associativity, when "$1" is 1, the [ 1 -eq $1 ] returns success, then lets nocmd run which doesn't exist and shell will return error exit status, the whole group will have exit status of fail, hence `"no" is echoed.



              By contrast, in your if statement



              if [ 1 -eq $1 ]; then
              echo "yes"
              else
              echo "no"
              fi


              which route to take depends only on exit status of [ portion. In [ 1 -eq "$1" ] && echo "Yes" || echo "no" echo also plays role as to whether or not echo "no" runs.



              Your second if statement example is also different



              if [ 1 -eq $1 ]; then
              nocmd "yes"
              if [ $? -ne 0 ]; then
              echo "no"
              fi
              else
              echo "no"
              fi


              The echo "no" after else doesn't depend on what happens to nocmd as in the chaining of logical operators. Sure you still do the echo "no" part after doing nocmd, but here its exit status isn't grouped together with the whole if portion to which it belongs.






              share|improve this answer


























                up vote
                3
                down vote













                What you're missing is that && and || operate on exit status of commands to the left of them - left associativity. You have here some group of commands || echo "no", and no will be echoed if and only if that group of commands returns non-success exit status.



                What is that group of commands ? In first case you have [ 1 -eq "$1" ] && echo "yes". If [ portion failed, that'd be counted as fail exit status for [ 1 -eq "$1" ] && echo "yes", therefore you'd echo "no" would run. Also because of left associativity, when "$1" is 1, the [ 1 -eq $1 ] returns success, then lets nocmd run which doesn't exist and shell will return error exit status, the whole group will have exit status of fail, hence `"no" is echoed.



                By contrast, in your if statement



                if [ 1 -eq $1 ]; then
                echo "yes"
                else
                echo "no"
                fi


                which route to take depends only on exit status of [ portion. In [ 1 -eq "$1" ] && echo "Yes" || echo "no" echo also plays role as to whether or not echo "no" runs.



                Your second if statement example is also different



                if [ 1 -eq $1 ]; then
                nocmd "yes"
                if [ $? -ne 0 ]; then
                echo "no"
                fi
                else
                echo "no"
                fi


                The echo "no" after else doesn't depend on what happens to nocmd as in the chaining of logical operators. Sure you still do the echo "no" part after doing nocmd, but here its exit status isn't grouped together with the whole if portion to which it belongs.






                share|improve this answer
























                  up vote
                  3
                  down vote










                  up vote
                  3
                  down vote









                  What you're missing is that && and || operate on exit status of commands to the left of them - left associativity. You have here some group of commands || echo "no", and no will be echoed if and only if that group of commands returns non-success exit status.



                  What is that group of commands ? In first case you have [ 1 -eq "$1" ] && echo "yes". If [ portion failed, that'd be counted as fail exit status for [ 1 -eq "$1" ] && echo "yes", therefore you'd echo "no" would run. Also because of left associativity, when "$1" is 1, the [ 1 -eq $1 ] returns success, then lets nocmd run which doesn't exist and shell will return error exit status, the whole group will have exit status of fail, hence `"no" is echoed.



                  By contrast, in your if statement



                  if [ 1 -eq $1 ]; then
                  echo "yes"
                  else
                  echo "no"
                  fi


                  which route to take depends only on exit status of [ portion. In [ 1 -eq "$1" ] && echo "Yes" || echo "no" echo also plays role as to whether or not echo "no" runs.



                  Your second if statement example is also different



                  if [ 1 -eq $1 ]; then
                  nocmd "yes"
                  if [ $? -ne 0 ]; then
                  echo "no"
                  fi
                  else
                  echo "no"
                  fi


                  The echo "no" after else doesn't depend on what happens to nocmd as in the chaining of logical operators. Sure you still do the echo "no" part after doing nocmd, but here its exit status isn't grouped together with the whole if portion to which it belongs.






                  share|improve this answer














                  What you're missing is that && and || operate on exit status of commands to the left of them - left associativity. You have here some group of commands || echo "no", and no will be echoed if and only if that group of commands returns non-success exit status.



                  What is that group of commands ? In first case you have [ 1 -eq "$1" ] && echo "yes". If [ portion failed, that'd be counted as fail exit status for [ 1 -eq "$1" ] && echo "yes", therefore you'd echo "no" would run. Also because of left associativity, when "$1" is 1, the [ 1 -eq $1 ] returns success, then lets nocmd run which doesn't exist and shell will return error exit status, the whole group will have exit status of fail, hence `"no" is echoed.



                  By contrast, in your if statement



                  if [ 1 -eq $1 ]; then
                  echo "yes"
                  else
                  echo "no"
                  fi


                  which route to take depends only on exit status of [ portion. In [ 1 -eq "$1" ] && echo "Yes" || echo "no" echo also plays role as to whether or not echo "no" runs.



                  Your second if statement example is also different



                  if [ 1 -eq $1 ]; then
                  nocmd "yes"
                  if [ $? -ne 0 ]; then
                  echo "no"
                  fi
                  else
                  echo "no"
                  fi


                  The echo "no" after else doesn't depend on what happens to nocmd as in the chaining of logical operators. Sure you still do the echo "no" part after doing nocmd, but here its exit status isn't grouped together with the whole if portion to which it belongs.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Jan 30 at 17:29

























                  answered Jan 30 at 17:20









                  Sergiy Kolodyazhnyy

                  7,63311547




                  7,63311547












                      Popular posts from this blog

                      How to check contact read email or not when send email to Individual?

                      Bahrain

                      Postfix configuration issue with fips on centos 7; mailgun relay