如何在bash中防止嵌套函数失败被忽略

huangapple go评论63阅读模式
英文:

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

感谢这些评论者:

还有这些支持资源:

我使用子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:

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

huangapple
  • 本文由 发表于 2023年8月8日 23:40:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76861137.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定