How to pipe the stdout of a command, depending on the result of the exit code

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











up vote
1
down vote

favorite












Expanding from this question, we have a use case where we want to pipe the stdout of a command depending on whether that command succeeded or failed.



We start with a basic pipe



command | grep -P "foo"


However we notice that sometimes command does not output anything to stdout, but does have an exit code of 0. We want to ignore this case and only apply the grep when the exit code is 1



For a working example, we could implement a command like this:



OUTPUT=$(command) # exit code is 0 or 1
RESULT=$?
if [ $RESULT -eq 0 ]; then
return $RESULT; # if the exit code is 0 then we simply pass it forward
else
grep -P "foo" <<< $OUTPUT; # otherwise check if the stdout contains "foo"
fi


but this has a number of disadvantages, namely that you have to write a script, meaning you can't just execute it in the console.
It also seems somewhat amateurish.



For a more concise syntax, I'm imagining a fictional ternary operator which pipes if the exit code is 1, otherwise it passes the exit code forwards.



command |?1 grep -P "foo" : $?


Is there a series of operators and utils that will achieve this result?










share|improve this question







New contributor




I'll Eat My Hat is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.























    up vote
    1
    down vote

    favorite












    Expanding from this question, we have a use case where we want to pipe the stdout of a command depending on whether that command succeeded or failed.



    We start with a basic pipe



    command | grep -P "foo"


    However we notice that sometimes command does not output anything to stdout, but does have an exit code of 0. We want to ignore this case and only apply the grep when the exit code is 1



    For a working example, we could implement a command like this:



    OUTPUT=$(command) # exit code is 0 or 1
    RESULT=$?
    if [ $RESULT -eq 0 ]; then
    return $RESULT; # if the exit code is 0 then we simply pass it forward
    else
    grep -P "foo" <<< $OUTPUT; # otherwise check if the stdout contains "foo"
    fi


    but this has a number of disadvantages, namely that you have to write a script, meaning you can't just execute it in the console.
    It also seems somewhat amateurish.



    For a more concise syntax, I'm imagining a fictional ternary operator which pipes if the exit code is 1, otherwise it passes the exit code forwards.



    command |?1 grep -P "foo" : $?


    Is there a series of operators and utils that will achieve this result?










    share|improve this question







    New contributor




    I'll Eat My Hat is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.





















      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      Expanding from this question, we have a use case where we want to pipe the stdout of a command depending on whether that command succeeded or failed.



      We start with a basic pipe



      command | grep -P "foo"


      However we notice that sometimes command does not output anything to stdout, but does have an exit code of 0. We want to ignore this case and only apply the grep when the exit code is 1



      For a working example, we could implement a command like this:



      OUTPUT=$(command) # exit code is 0 or 1
      RESULT=$?
      if [ $RESULT -eq 0 ]; then
      return $RESULT; # if the exit code is 0 then we simply pass it forward
      else
      grep -P "foo" <<< $OUTPUT; # otherwise check if the stdout contains "foo"
      fi


      but this has a number of disadvantages, namely that you have to write a script, meaning you can't just execute it in the console.
      It also seems somewhat amateurish.



      For a more concise syntax, I'm imagining a fictional ternary operator which pipes if the exit code is 1, otherwise it passes the exit code forwards.



      command |?1 grep -P "foo" : $?


      Is there a series of operators and utils that will achieve this result?










      share|improve this question







      New contributor




      I'll Eat My Hat is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      Expanding from this question, we have a use case where we want to pipe the stdout of a command depending on whether that command succeeded or failed.



      We start with a basic pipe



      command | grep -P "foo"


      However we notice that sometimes command does not output anything to stdout, but does have an exit code of 0. We want to ignore this case and only apply the grep when the exit code is 1



      For a working example, we could implement a command like this:



      OUTPUT=$(command) # exit code is 0 or 1
      RESULT=$?
      if [ $RESULT -eq 0 ]; then
      return $RESULT; # if the exit code is 0 then we simply pass it forward
      else
      grep -P "foo" <<< $OUTPUT; # otherwise check if the stdout contains "foo"
      fi


      but this has a number of disadvantages, namely that you have to write a script, meaning you can't just execute it in the console.
      It also seems somewhat amateurish.



      For a more concise syntax, I'm imagining a fictional ternary operator which pipes if the exit code is 1, otherwise it passes the exit code forwards.



      command |?1 grep -P "foo" : $?


      Is there a series of operators and utils that will achieve this result?







      bash control-flow






      share|improve this question







      New contributor




      I'll Eat My Hat is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question







      New contributor




      I'll Eat My Hat is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question






      New contributor




      I'll Eat My Hat is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 22 mins ago









      I'll Eat My Hat

      82




      82




      New contributor




      I'll Eat My Hat is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      I'll Eat My Hat is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      I'll Eat My Hat is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          3
          down vote



          accepted










          Commands in a pipeline run concurrently, that's the whole point of pipes, and inter-process communication mechanism.



          In:



          cmd1 | cmd2


          cmd1 and cmd2 are started at the same time, cmd2 processes the data that cmd1 writes as it comes.



          If you wanted cmd2 to be started only if cmd1 had failed, you'd have to start cmd2 after cmd1 has finished and reported its exit status, so you couldn't use a pipe, you'd have to use a temporary file that holds all the data the cmd1 has produced:



           cmd1 > file || cmd2 < file; rm -f file


          Or store in memory like in your example but that has a number of other issues (like $(...) removing all trailing newline characters, and most shells can't cope with NUL bytes in there, not to mention the scaling issues for large outputs).



          On Linux and with shells like zsh or bash that store here-documents and here-strings in temporary files, you could do:



           cmd2 <&3; 3<<< ignored


          To let the shell deal with the temp file creation and clean-up.



          Also note that there's nothing stopping you running any code in the console. Your "script" can be entered just the same at the prompt of an interactive shell (except for the return part that assumes the code is in a function), though you can simplify it to:



          output=$(cmd) || grep foo <<< "$output"





          share|improve this answer






















          • Excellent. Both cmd1 > file || cmd2 < file and output=$(cmd) || grep foo <<< "$output" achieve the results in full. With the former syntax I have to later clean up by removing the file, but this is not a big deal and provides quite a few options. Thanks.
            – I'll Eat My Hat
            3 mins ago










          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',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );






          I'll Eat My Hat is a new contributor. Be nice, and check out our Code of Conduct.









           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f477820%2fhow-to-pipe-the-stdout-of-a-command-depending-on-the-result-of-the-exit-code%23new-answer', 'question_page');

          );

          Post as a guest






























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          3
          down vote



          accepted










          Commands in a pipeline run concurrently, that's the whole point of pipes, and inter-process communication mechanism.



          In:



          cmd1 | cmd2


          cmd1 and cmd2 are started at the same time, cmd2 processes the data that cmd1 writes as it comes.



          If you wanted cmd2 to be started only if cmd1 had failed, you'd have to start cmd2 after cmd1 has finished and reported its exit status, so you couldn't use a pipe, you'd have to use a temporary file that holds all the data the cmd1 has produced:



           cmd1 > file || cmd2 < file; rm -f file


          Or store in memory like in your example but that has a number of other issues (like $(...) removing all trailing newline characters, and most shells can't cope with NUL bytes in there, not to mention the scaling issues for large outputs).



          On Linux and with shells like zsh or bash that store here-documents and here-strings in temporary files, you could do:



           cmd2 <&3; 3<<< ignored


          To let the shell deal with the temp file creation and clean-up.



          Also note that there's nothing stopping you running any code in the console. Your "script" can be entered just the same at the prompt of an interactive shell (except for the return part that assumes the code is in a function), though you can simplify it to:



          output=$(cmd) || grep foo <<< "$output"





          share|improve this answer






















          • Excellent. Both cmd1 > file || cmd2 < file and output=$(cmd) || grep foo <<< "$output" achieve the results in full. With the former syntax I have to later clean up by removing the file, but this is not a big deal and provides quite a few options. Thanks.
            – I'll Eat My Hat
            3 mins ago














          up vote
          3
          down vote



          accepted










          Commands in a pipeline run concurrently, that's the whole point of pipes, and inter-process communication mechanism.



          In:



          cmd1 | cmd2


          cmd1 and cmd2 are started at the same time, cmd2 processes the data that cmd1 writes as it comes.



          If you wanted cmd2 to be started only if cmd1 had failed, you'd have to start cmd2 after cmd1 has finished and reported its exit status, so you couldn't use a pipe, you'd have to use a temporary file that holds all the data the cmd1 has produced:



           cmd1 > file || cmd2 < file; rm -f file


          Or store in memory like in your example but that has a number of other issues (like $(...) removing all trailing newline characters, and most shells can't cope with NUL bytes in there, not to mention the scaling issues for large outputs).



          On Linux and with shells like zsh or bash that store here-documents and here-strings in temporary files, you could do:



           cmd2 <&3; 3<<< ignored


          To let the shell deal with the temp file creation and clean-up.



          Also note that there's nothing stopping you running any code in the console. Your "script" can be entered just the same at the prompt of an interactive shell (except for the return part that assumes the code is in a function), though you can simplify it to:



          output=$(cmd) || grep foo <<< "$output"





          share|improve this answer






















          • Excellent. Both cmd1 > file || cmd2 < file and output=$(cmd) || grep foo <<< "$output" achieve the results in full. With the former syntax I have to later clean up by removing the file, but this is not a big deal and provides quite a few options. Thanks.
            – I'll Eat My Hat
            3 mins ago












          up vote
          3
          down vote



          accepted







          up vote
          3
          down vote



          accepted






          Commands in a pipeline run concurrently, that's the whole point of pipes, and inter-process communication mechanism.



          In:



          cmd1 | cmd2


          cmd1 and cmd2 are started at the same time, cmd2 processes the data that cmd1 writes as it comes.



          If you wanted cmd2 to be started only if cmd1 had failed, you'd have to start cmd2 after cmd1 has finished and reported its exit status, so you couldn't use a pipe, you'd have to use a temporary file that holds all the data the cmd1 has produced:



           cmd1 > file || cmd2 < file; rm -f file


          Or store in memory like in your example but that has a number of other issues (like $(...) removing all trailing newline characters, and most shells can't cope with NUL bytes in there, not to mention the scaling issues for large outputs).



          On Linux and with shells like zsh or bash that store here-documents and here-strings in temporary files, you could do:



           cmd2 <&3; 3<<< ignored


          To let the shell deal with the temp file creation and clean-up.



          Also note that there's nothing stopping you running any code in the console. Your "script" can be entered just the same at the prompt of an interactive shell (except for the return part that assumes the code is in a function), though you can simplify it to:



          output=$(cmd) || grep foo <<< "$output"





          share|improve this answer














          Commands in a pipeline run concurrently, that's the whole point of pipes, and inter-process communication mechanism.



          In:



          cmd1 | cmd2


          cmd1 and cmd2 are started at the same time, cmd2 processes the data that cmd1 writes as it comes.



          If you wanted cmd2 to be started only if cmd1 had failed, you'd have to start cmd2 after cmd1 has finished and reported its exit status, so you couldn't use a pipe, you'd have to use a temporary file that holds all the data the cmd1 has produced:



           cmd1 > file || cmd2 < file; rm -f file


          Or store in memory like in your example but that has a number of other issues (like $(...) removing all trailing newline characters, and most shells can't cope with NUL bytes in there, not to mention the scaling issues for large outputs).



          On Linux and with shells like zsh or bash that store here-documents and here-strings in temporary files, you could do:



           cmd2 <&3; 3<<< ignored


          To let the shell deal with the temp file creation and clean-up.



          Also note that there's nothing stopping you running any code in the console. Your "script" can be entered just the same at the prompt of an interactive shell (except for the return part that assumes the code is in a function), though you can simplify it to:



          output=$(cmd) || grep foo <<< "$output"






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited 11 mins ago

























          answered 17 mins ago









          Stéphane Chazelas

          289k54537875




          289k54537875











          • Excellent. Both cmd1 > file || cmd2 < file and output=$(cmd) || grep foo <<< "$output" achieve the results in full. With the former syntax I have to later clean up by removing the file, but this is not a big deal and provides quite a few options. Thanks.
            – I'll Eat My Hat
            3 mins ago
















          • Excellent. Both cmd1 > file || cmd2 < file and output=$(cmd) || grep foo <<< "$output" achieve the results in full. With the former syntax I have to later clean up by removing the file, but this is not a big deal and provides quite a few options. Thanks.
            – I'll Eat My Hat
            3 mins ago















          Excellent. Both cmd1 > file || cmd2 < file and output=$(cmd) || grep foo <<< "$output" achieve the results in full. With the former syntax I have to later clean up by removing the file, but this is not a big deal and provides quite a few options. Thanks.
          – I'll Eat My Hat
          3 mins ago




          Excellent. Both cmd1 > file || cmd2 < file and output=$(cmd) || grep foo <<< "$output" achieve the results in full. With the former syntax I have to later clean up by removing the file, but this is not a big deal and provides quite a few options. Thanks.
          – I'll Eat My Hat
          3 mins ago










          I'll Eat My Hat is a new contributor. Be nice, and check out our Code of Conduct.









           

          draft saved


          draft discarded


















          I'll Eat My Hat is a new contributor. Be nice, and check out our Code of Conduct.












          I'll Eat My Hat is a new contributor. Be nice, and check out our Code of Conduct.











          I'll Eat My Hat is a new contributor. Be nice, and check out our Code of Conduct.













           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f477820%2fhow-to-pipe-the-stdout-of-a-command-depending-on-the-result-of-the-exit-code%23new-answer', 'question_page');

          );

          Post as a guest













































































          Comments

          Popular posts from this blog

          What does second last employer means? [closed]

          Installing NextGIS Connect into QGIS 3?

          One-line joke