为何Bash脚本中子shell内的set -e未触发||分支?脚本对比解析
Bash中
set -e与||组合时的行为解析 第一个脚本及现象
脚本代码:
#!/bin/bash ( set -x -e false echo e1 $? ) || { echo e2 $? exit 1 }
实际输出:
+ false + echo e1 1 e1 1
疑问:为什么完全看不到含“e2”的输出?
对比脚本及预期输出
对比脚本:
#!/bin/bash ( set -x -e false echo e1 $? true ) echo e2 $?
预期输出:
$ bash /tmp/foo.sh + false e2 1 $
两种场景里set -x -e都被限定在子shell作用域内,但第一个脚本的||好像没起作用?
Bash版本信息:
$ bash --version bash --version GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu) Copyright (C) 2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. $
核心原因:set -e的生效规则
set -e(即errexit选项)的核心规则是:当命令是||/&&列表、管道的一部分时,该命令返回非0状态码不会触发脚本退出,除非它是整个列表/管道的最后一个命令。
第一个脚本的执行流程
- 子shell内开启
set -x -e,但因为这个子shell是||表达式的左侧部分,set -e的“错误即退出”规则被抑制。 - 执行
false返回非0,但Bash不会直接退出子shell,而是继续执行后续命令。 echo e1 $?执行成功,返回状态码0,这成为了整个子shell的最终退出状态。- 由于子shell退出状态是0,
||右侧的代码块不会被执行,自然看不到e2的输出。
第二个脚本的执行流程
- 子shell不属于
||/&&列表的一部分,set -e规则正常生效。 false返回非0后,子shell直接退出,后续的echo e1 $?和true都不会执行。- 子shell的退出状态是
false的返回值1,所以外部的echo e2 $?输出e2 1,符合预期。
内容的提问来源于stack exchange,提问作者bgoodr
相关产品推荐
相关产品推荐

