英文:
How to prevent nested function failures being missed in bash
问题
以下是代码的中文翻译:
#!/usr/bin/env bash
set -Eeuo pipefail
shopt -s huponexit
shopt -s inherit_errexit
function child_function {
return 1
}
function parent_function {
child_function
echo "父进程注意到子进程的退出码为 $?"
}
function grandparent_function {
local ec
ec=0 && parent_function || ec="$?"
echo "祖父进程注意到父进程的退出码为 $ec"
}
grandparent_function
令人惊讶的是,上述代码的输出结果为:
父进程注意到子进程的退出码为 1
祖父进程注意到父进程的退出码为 0
将代码修改为:
#!/usr/bin/env bash
set -Eeuo pipefail
shopt -s huponexit
shopt -s inherit_errexit
function child_function {
return 1
}
function parent_function {
child_function || return "$?"
echo "父进程注意到子进程的退出码为 $?"
}
function grandparent_function {
local ec
ec=0 && parent_function || ec="$?"
echo "祖父进程注意到父进程的退出码为 $ec"
}
grandparent_function
将返回预期结果:
祖父进程注意到父进程的退出码为 1
是否需要设置其他选项来修复这个问题?还是这是bash的一个错误?
我认为这是一个错误的原因是,将代码修改为不使用 || ec="$?"
将会遵守 -e/errexit
选项(如果命令以非零状态退出,则立即退出),并且每个失败的函数都会立即退出:
#!/usr/bin/env bash
set -Eeuo pipefail
shopt -s huponexit
shopt -s inherit_errexit
function child_function {
return 1
}
function parent_function {
child_function
echo "父进程注意到子进程的退出码为 $?"
}
function grandparent_function {
parent_function
echo "祖父进程注意到父进程的退出码为 $?"
}
grandparent_function
不会输出任何内容,并返回退出码 1。
英文:
The following code:
#!/usr/bin/env bash
set -Eeuo pipefail
shopt -s huponexit
shopt -s inherit_errexit
function child_function {
return 1
}
function parent_function {
child_function
echo "parent noticed child exit code as $?"
}
function grandparent_function {
local ec
ec=0 && parent_function || ec="$?"
echo "grandparent noticed parent exit code as $ec"
}
grandparent_function
Will surprisingly output:
parent noticed child exit code as 1
grandparent noticed parent exit code as 0
Changing the code to:
#!/usr/bin/env bash
set -Eeuo pipefail
shopt -s huponexit
shopt -s inherit_errexit
function child_function {
return 1
}
function parent_function {
child_function || return "$?"
echo "parent noticed child exit code as $?"
}
function grandparent_function {
local ec
ec=0 && parent_function || ec="$?"
echo "grandparent noticed parent exit code as $ec"
}
grandparent_function
Returns the expected result of:
grandparent noticed parent exit code as 1
Is there an additional setting that I need to set to fix this? Or is this a bug in bash?
The reason I believe it is a bug, is that changing the code to not use the || ec="$?"
will respect the -e/errexit
option (Exit immediately if a command exits with a non-zero status) and have each failed function exit immediately:
#!/usr/bin/env bash
set -Eeuo pipefail
shopt -s huponexit
shopt -s inherit_errexit
function child_function {
return 1
}
function parent_function {
child_function
echo "parent noticed child exit code as $?"
}
function grandparent_function {
parent_function
echo "grandparent noticed parent exit code as $?"
}
grandparent_function
Outputs nothing and returns exit code 1
答案1
得分: 1
感谢这些评论者:
还有这些支持资源:
- https://stackoverflow.com/a/32201766/130638
- https://stackoverflow.com/a/70992989/130638
- https://unix.stackexchange.com/q/447519/50703
- https://mywiki.wooledge.org/BashPitfalls#set_-euo_pipefail
- https://unix.stackexchange.com/a/645365/50703
- https://stackoverflow.com/q/19789102/130638
- https://www.austingroupbugs.net/view.php?id=537
我使用子shell技术为问题的代码示例创建了这个解决方法:
#!/usr/bin/env bash
set -e
function child_function {
return 1
}
function parent_function {
child_function
echo "parent noticed child exit code as $?"
}
function grandparent_function {
local ec=0
set +e; (set -e; parent_function); ec="$?"; set -e
echo "grandparent noticed parent exit code as $ec"
}
grandparent_function
然而,子shell技术会阻止副作用,因为修改不会逃离子shell。
我花了几天时间研究了这个问题,并创建了一个包含各种技术的gist,其中包括一个可以处理副作用的方法:
https://gist.github.com/balupton/21ded5cefc26dc20833e6ed606209e1b
英文:
Thanks to the commenters:
And these supporting resources:
- https://stackoverflow.com/a/32201766/130638
- https://stackoverflow.com/a/70992989/130638
- https://unix.stackexchange.com/q/447519/50703
- https://mywiki.wooledge.org/BashPitfalls#set_-euo_pipefail
- https://unix.stackexchange.com/a/645365/50703
- https://stackoverflow.com/q/19789102/130638
- https://www.austingroupbugs.net/view.php?id=537
I created this workaround for the question's code sample using the subshell technique:
#!/usr/bin/env bash
set -e
function child_function {
return 1
}
function parent_function {
child_function
echo "parent noticed child exit code as $?"
}
function grandparent_function {
local ec=0
set +e; (set -e; parent_function); ec="$?"; set -e
echo "grandparent noticed parent exit code as $ec"
}
grandparent_function
However, the subshell technique prevents side effects, as modifications do not escape the subshell.
I spent a few more days on this issue, and created a gist with various techniques, including one that works with side effects:
https://gist.github.com/balupton/21ded5cefc26dc20833e6ed606209e1b
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论