Home > Back-end >  BASH - 'exit 1' failed in loop inside another loop
BASH - 'exit 1' failed in loop inside another loop

Time:01-04

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.

CodePudding user response:

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.

  •  Tags:  
  • bash
  • Related