BASH - “exit 1”在另一个循环内的循环中失败

pro*_*mbc 2 bash

以下代码不会在第一次exit 1调用时退出error_exit。我缺少什么?

#!/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
Run Code Online (Sandbox Code Playgroud)

这是我获得的输出。


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.
Run Code Online (Sandbox Code Playgroud)

mar*_*rkp 7

在我的bash环境中,exit在子进程中调用不会中止父进程,例如:

$ echo "1 2 3" | exit                   # does not exit my console but instead ...
$                                       # presents me with the command prompt
Run Code Online (Sandbox Code Playgroud)

在您的情况下,您有 pipeline: find | sort | while,因此python || error_exit在子进程中调用 ,这又意味着将exit 1应用于子进程而不是(父)脚本。

一种确保(内部)while(从而确保exit 1)不在子进程中运行的解决方案:

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

笔记:

  • 我建议习惯这种结构,因为它还解决了另一个常见问题......
  • 分配给子流程中变量的值不会“向上”传递到父流程
  • 子进程的行为在其他 shell 中可能有所不同

当然,同样的问题也适用于父/外while循环,因此,如果目标是将exit 1应用于整个脚本,那么也需要为父/外循环实现相同的结构find | sort | while

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)
Run Code Online (Sandbox Code Playgroud)

附加注释复制自GordonDavisson 对此答案的编辑

请注意,该<( )构造(“进程替换”)并非在所有 shell 中都可用,甚至在 bash 中(当它处于 sh 兼容模式时)(即当它作为sh或调用时/bin/sh)中也不可用。因此,请务必在脚本中使用显式 bash shebang(例如#!/bin/bash#!/usr/bin/env bash),并且不要通过使用命令运行脚本来覆盖它 sh