即使使用“set -e”,for 循环中的函数调用也不会失败

Ahm*_*gle 5 bash

考虑以下简单的 bash 脚本:

#!/bin/bash
set -eou pipefail
IFS=$'\n\t'

gen() {
  seq 0 3
}

for c in $(gen); do
  echo c
done

echo "finish"
Run Code Online (Sandbox Code Playgroud)

它已经set -e设置,所以当出现故障时,它应该以非零退出代码退出。

它将调用gen函数并打印 的输出seq 0 3,将打印finish并以 code=0 退出。

如果我修改gen失败,例如,通过调用seqqq命令(不存在)来代替:

$ ./script.sh; echo $?
./script.sh: line 6: seqqq: command not found
finish
0
Run Code Online (Sandbox Code Playgroud)

set -e它从子 shell 打印错误消息,它不会像预期的那样立即失败并立即退出(使用非零代码) ;它继续执行并以 code=0 退出。

这背后的解释是什么?请注意,如果我只是用我的 for 循环替换,它会按预期失败:

#!/bin/bash
set -eou pipefail
IFS=$'\n\t'

gen() {
  seqqq 0 3
}

gen # <-- fails and exits here with code=127

echo "finish"
Run Code Online (Sandbox Code Playgroud)

cod*_*ter 4

看起来set -e在命令替换的上下文中无效,如下所示:

for c in $(gen); do
  echo c
done
Run Code Online (Sandbox Code Playgroud)

但是,set -e在直接函数调用的上下文中确实有效,如下所示:

gen
Run Code Online (Sandbox Code Playgroud)

使用 . 编写可靠的 shell 脚本是困难或几乎不可能的set -e。请改用显式错误处理。您可以在这里阅读更多相关信息:BashFAQ/105