当前位置: 首页 > 知识库问答 >
问题:

为什么bash errexit在函数调用中的行为不如预期?

毛成济
2023-03-14

在bash手册页中,它指出:

如果管道(可能由单个简单命令组成)、
括号中包含的子shell命令,或作为大括号中包含的命令列表的一部分执行的其中一个命令。。。

所以我假设一个函数应该被视为一个用大括号括起来的命令列表。但是,如果将条件应用于函数调用,errexit将不再在函数体中存在,它将在返回之前执行整个命令列表。即使在函数内部显式创建了一个子shell,并为该子shell启用了errexit,命令列表中的所有命令都会执行。下面是一个简单的例子来说明这个问题:

function a() { b ; c ; d ; e ; }
function ap() { { b ; c ; d ; e ; } ; }
function as() { ( set -e ; b ; c ; d ; e ) ; }
function b() { false ; }
function c() { false ; }
function d() { false ; }
function e() { false ; }
( set -Eex ; a )
+ a
+ b
+ false
( set -Eex ; ap )
+ ap
+ b
+ false
( set -Eex ; as )
+ as
+ set -e
+ b
+ false

现在如果我对每一个应用一个条件。。。

( set -Eex ; a || false )
+ a
+ b
+ false
+ c
+ false
+ d
+ false
+ e
+ false
+ false
( set -Eex ; ap || false )
+ ap
+ b
+ false
+ c
+ false
+ d
+ false
+ e
+ false
+ false
( set -Eex ; as )
+ as
+ set -e
+ b
+ false
+ c
+ false
+ d
+ false
+ e
+ false
+ false

共有3个答案

扈高逸
2023-03-14

这不是对原始问题的回答,而是针对根本问题的解决方案:设置错误陷阱:

function on_error() {
    echo "error happened!"
}
trap on_error ERR

echo "OK so far"
false
echo "this line should not execute"

行为本身的原因在其他答案中得到了正确的解释(根据手册和POSIX,基本上是预期的bash行为):https://stackoverflow.com/a/19789651/1091436

海翔宇
2023-03-14

bug bash邮件列表中Eric Blake对函数的解释更加明确:

简短的回答:历史兼容性。

...

事实上,POSIX要求的正确行为(即在f()的整个主体期间完全忽略“set-e”,因为f是在忽略“set-e”的上下文中调用的)并不直观。但它是标准化的,所以我们必须接受它。

以及一些关于是否可以利用set-e来实现所需行为的单词:

因为一旦你处在一个忽略“set-e”的上下文中,历史行为就是,对于被忽略的上下文中的整个代码体,没有进一步的方法来重新打开它。30年前,在真正考虑外壳功能之前,它就是这样做的,我们被这个糟糕的设计决策所困扰。

段超
2023-03-14

你开始引用手册,但后来你删掉了解释这种行为的部分,这是在下一句:

-e如果管道(可能由单个简单命令、括号内的子shell命令或作为大括号内命令列表的一部分执行的其中一个命令组成)返回非零状态,则立即退出。如果失败的命令是紧跟在之后的命令列表的一部分,而直到关键字,在if语句中测试的一部分,在语句中执行的任何命令的一部分,则shell不会退出

 类似资料:
  • 问题内容: 当我执行以下命令时,几秒钟后会被调用,并且每秒钟都会继续执行而不会出现任何问题: 但是,这将 立即 执行 , 并在第二次迭代时引发以下错误: 错误: 似乎是/正在某种程度上成为。有人可以解释为什么这是预期的行为(无论如何,我认为是这样)? 我可以很轻松地解决这个问题,但是我很好奇为什么它会这样工作-使得参数值的传递变得不那么方便,因为我无法在语句内部进行操作。 问题答案: 接受功能对象

  • 当调用中列出的函数时,我无法找到适当的源代码来说明预期的行为。 我的观察是,创建一个日志条目,上面写着 [04-Sep-2014 16:17:55 UTC]PHP警告:出于安全原因,{file}{line}中的curl_exec()已被禁用 但是在这种情况下函数返回什么呢?我的意思是,返回的记录是什么?

  • 我使用从iPython笔记本下载CSV时建议的代码动态构建javascript代码,并在从jupyter笔记本调用时使用python中的javascript()将其传递给浏览器。代码工作得很好。如果我在python函数中嵌入相同的代码,并从同一个jupyter笔记本调用python函数,那么python中的调用Javascript()将不再有效。如何使可重用功能正常工作? 我正在Windows 1

  • 需要您的帮助,我不明白为什么会出现以下错误,我不是专业的postgresql开发人员。。 正如你可以看到创建的函数,那么为什么函数不存在? 错误:函数logintry(未知,未知,带时区的时间戳,整数)不存在第1行:选择logintry('Jon.Jones88@gmail.com','_@kjhfdb987',...^HINT:没有函数匹配给定的名称和参数类型。您可能需要添加显式类型转换。SQL

  • 问题内容: 我有一个想法,可能是因为我正在做一些样式设计来更改单选按钮,但是我不确定。我正在设置一个onClick事件,该事件两次调用了我的函数。我已删除它以确保它没有在其他地方被触发,并且onClick似乎是罪魁祸首。 我的功能目前仅是运输选项的简单控制台日志: 如果没有任何理由可以在这里看到为什么会发生这种情况,我可以发布其余代码,但是有很多方面,我认为这与之无关,但是我认为这是一个很好的起点

  • 编辑:由于代码剪贴不会重现错误-这里有一个指向github repo的链接:(代码远未完成) https://github.com/altruios/clicker-game 我现在已经在两台计算机上运行了它——这两台计算机都有相同的行为,而代码剪报并没有显示出来。 因此,我正在构建一个clicker游戏来学习react,我不明白为什么这段代码会以这种方式运行: 在主应用程序中,我有以下功能: 那