Search code examples
linuxbashshellstdoutexecution

bash script exits unexpectedly after returning from function


This is a follow up question to my last question on stack overflow. I'll cut down the script to the essential parts, but if s.o. thinks, it might be helpful to know what the script does, you may look into the other question.

 #!/usr/bin/env bash
 set -eu -o pipefail

 declare -a framelist


 #Print all results

 function output_values() {
   echo "Results!";
 }

 #parsing information from stdin

 function parser () {

   while read tc;
     do

      if [ -z "$tc" ]; then
        continue
      fi

      #Evaluation and saving result to array

      echo $result_value;

      framelist+=($result_value);

      if (( <<some abort condition>> )); then
        exec 0>&-
        echo "Last result: $result_value";
        return 0
      fi

     done
 }

 some_command_writing_to_stdout | parser $2;
 output_values;

The script executes the command and pipes the output to my local function which finally returns a result at the line echo "Last result: $result_value"; as it is intended to do. After this, it shall terminate the command that provides the data which is parsed in this function - this works, too.

When reaching return 0, I'd think, the next line of the script (right below of the command) output_values; should be executed, but it is not.

Even if I call the output_values function directly before the echo line, that prints the result in the parser function, it is not executed.

It gets even more weird, as I can comment out exec 0>&- and all behaves just the same. Even the command that should be terminated by this line, gets terminated, as soon as the parser function is being exited.

What do I have to change to be able to work on with the results of my parser function, after it returns? This can't be intended behavior.

Regards

Manuel


Solution

  • Let's have a look at man bash, section on pipefail:

    pipefail

    If set, the return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands in the pipeline exit successfully. This option is disabled by default.

    Combined with set -e, which will exit whenever a command (pipeline) exits with non-zero exit status, the only logical conclusion is: your some_command_writing_to_stdout must be exiting with a non-zero exit status (because evidently, parser exist with 0).

    This would explain why the next command in the pipeline (parser) get executed, and why your script finishes after that.

    It's easy enough to verify this. Just replace the penultimate statement with:

    (some_command_writing_to_stdout || true) | parser $2