3

The following code doesn't exit at the first exit 1 from the call of error_exit. What am I missing?

#!/bin/bash

THIS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
JINJANG_DIR="$(cd "$THIS_DIR/../.." && pwd)"
DATAS_DIR="$THIS_DIR/datas"

error_exit() {
    echo ""
    echo "ERROR - Following command opens the file that has raised an error."
    echo ""
    echo "  > open \"$1\""
    exit 1
}


cd "$DATAS_DIR"

find . -name 'datas.*'  -type f | sort  | while read -r datafile
do
    localdir="$(dirname $datafile)"
    
    echo "    * Testing ''$localdir''."
    
    filename=$(basename "$datafile")
    ext=${filename##*.}
    
    if [ "$ext" == "py" ]
    then
        unsafe="-u"
    else
        unsafe=""
    fi
    
    datas="$DATAS_DIR/$datafile"

    find . -name 'template.*'  -type f | sort  | while read -r template
    do
        filename=$(basename "$template")
        ext=${filename##*.}

        template="$DATAS_DIR/$template"
        outputfound="$DATAS_DIR/$localdir/output_found.$ext"
        
        cd "$JINJANG_DIR"
        python -m src $UNSAFE "$DATA" "$TEMPLATE" "$OUTPUTFOUND"  || error_exit "$localdir"
    done

    cd "$DATAS_DIR"
done

Here is the output I obtain.


ERROR - Following command opens the file that has raised an error.

  > open "./html/no-param-1"
    * Testing ''./html/no-param-2''.

ERROR - Following command opens the file that has raised an error.

  > open "./html/no-param-2"
    * Testing ''./latex/no-param-1''.

ERROR - Following command opens the file that has raised an error.

  > open "./latex/no-param-1"
    * Testing ''./latex/no-param-2''.

ERROR - Following command opens the file that has raised an error.
2

1 Answer 1

7

In my bash environment invoking exit in a subprocess does not abort the parent process, eg:

$ echo "1 2 3" | exit                   # does not exit my console but instead ...
$                                       # presents me with the command prompt

In your case you have the pipeline: find | sort | while, so the python || error_exit is being called within a subprocess which in turn means the exit 1 will apply to the subprocess but not the (parent) script.

One solution that insures the (inner) while (and thus the exit 1) is not run in a subprocess:

while read -r template
do
    ... snip ...
    python ... || error_exit
    ... snip ...
done < <(find . -name 'template.*'  -type f | sort)

NOTES:

  • I'd recommend getting used to this structure as it also addresses another common issue ...
  • values assigned to variables in a subprocess are not passed 'up' to the parent process
  • subprocess behavior may differ in other shells

Of course, this same issue applies to the parent/outer while loop so, if the objective is for the exit 1 to apply to the entire script then this same structure will need to be implemented for the parent/outer find | sort | while, too:

while read -r datafile
do
    ... snip ...

    while read -r template
    do
        ... snip ...

        python ... || error_exit

    done < <(find . -name 'template.*'  -type f | sort)

    cd "$DATAS_DIR"
done < <(find . -name 'datas.*'  -type f | sort)

Additional note copied from GordonDavisson's edit of this answer:

Note that the <( ) construct ("process substitution") is not available in all shells, or even in bash when it's in sh-compatibility mode (i.e. when it's invoked as sh or /bin/sh). So be sure to use an explicit bash shebang (like #!/bin/bash or #!/usr/bin/env bash) in your script, and don't override it by running the script with the sh command.

Sign up to request clarification or add additional context in comments.

4 Comments

I proposed "Exit bash script within while loop" as a duplicate, but I think this is a better solution than the one there (though not as portable). Could you also add it as an answer there? (Oh, and I'd recommend adding a note that this only when bash is run as bash -- if you invoke it as sh or /bin/sh, process substitution is disabled.)
@GordonDavisson The answer in this post uses another simple technic. No?
Yep, just || exit 1 after the loop to propagate the error (which works fine for this specific issue, but doesn't help with the other things you mentioned).
@GordonDavisson Please read my question again. I had only one problem which was solved by this answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.