1

我似乎遇到了一个非常非常奇怪的不一致方式,dash并使用该选项bash检查错误情况。errexit

使用dashbash 使用set -e/set -o errexit选项,以下程序:

foo()
{
    echo pre
    bar=$(fail)
    echo post
}

foo

将打印以下内容(对于 的错误字符串略有不同dash):

pre
./foo.sh: line 4: fail: command not found
post

使用errexit选项,它将打印以下内容:

pre
./foo.sh: line 4: fail: command not found

然而,令人惊讶的是,如果barlocal,程序将始终echo同时具有prepost。更具体地说,同时使用dashbash 不使用我们errexit选项,以下程序:

foo()
{
    echo pre
    local bar=$(fail)
    echo post
}

foo

将打印以下内容:

pre
./foo.sh: line 4: fail: command not found
post

换句话说,似乎没有检查分配给局部变量的命令替换的返回值errexit,但如果变量是全局的,则检查。

如果两个外壳都没有发生这种情况,我会倾向于认为这只是一个极端情况下的错误。由于dash专门设计为符合 POSIX 标准,我想知道这种行为是否实际上是由 POSIX 标准指定的,尽管我很难想象这将如何有意义。

dash(1)有这个要说的errexit

如果不是交互式的,如果任何未经测试的命令失败,则立即退出。如果命令用于控制ifelifwhileuntil; ,则认为命令的退出状态是经过显式测试的。或者如果命令是“&&”或“||”的左侧操作数 操作员。

bash(1)有点冗长,但我很难理解它:

如果 a pipeline(可能由单个simple command)、 alist或 a compound command(见SHELL GRAMMAR上文)以非零状态退出,则立即退出。while如果失败的命令是紧跟在oruntil关键字之后的命令列表的一部分、在ifor保留字之后的测试的一部分、在or列表elif中执行的任何命令的一部分(除了最后or之后的命令),则 shell 不会退出管道中的命令但最后一个,或者如果命令的返回值与. 如果子 shell 以外的复合命令由于命令在被忽略时失败而返回非零状态,则 shell 不会退出。一个陷阱&&||&&||!-eERR,如果设置,则在 shell 退出之前执行。此选项分别适用于 shell 环境和每个子 shell 环境(见COMMAND EXECUTION ENVIRONMENT上文),并可能导致子 shell 在执行子 shell 中的所有命令之前退出。

如果复合命令或 shell 函数在-e被忽略的上下文中执行,则在复合命令或函数体中执行的任何命令都不会受到-e设置的影响,即使-e设置了并且命令返回失败状态。如果复合命令或 shell 函数在被忽略-e的上下文中执行时-e设置,则在复合命令或包含函数调用的命令完成之前,该设置将不起作用。

4

3 回答 3

4

TL;DR local“隐藏”其参数之一中出现的任何命令替换的退出状态的退出状态。


变量赋值的退出状态记录不充分(或者至少,我在快速浏览各种手册页和 POSIX 规范时找不到任何细节)。据我所知,退出状态被视为分配值中发生的最后一个命令替换的退出状态,如果没有命令替换,则为 0。非最终命令替换似乎包含在“测试”情况列表中,作为分配

foo=$(false)$(true)

不退出errexit设置。

local然而,它是一个命令本身,其退出状态通常为 0,与在其参数中出现的任何命令替换无关。也就是说,虽然

foo=$(false)

退出状态为 1,

local foo=$(false)

退出状态为 0,参数中的任何命令替换似乎都被视为“已测试” errexit

于 2015-11-21T14:21:50.087 回答
0

尝试这个:

#!/bin/bash
set -e

foo()
{
    echo pre
    local bar
    bar=$(fail)
    echo post
}

foo

exit

!!或者 !!

#!/bin/bash

foo()
{
    set -e
    echo pre
    local bar
    bar=$(fail)
    echo post
}

foo

exit

输出:

$ ./errexit_function 
pre
./errexit_function: line 8: fail: command not found
$ echo $?
127
于 2015-11-21T21:18:44.447 回答
0

据我所知,这是针对 bash 中的一个错误的解决方法,但试试这个,

#!/bin/bash
set -e

foo()
{
    echo true || return_value=$?
    echo the command returned a value of ${return_value:-0}
    $(fail) || return_value=$?
    echo the command returned a value of ${return_value:-0}
    echo post
}

foo

exit
于 2016-02-25T01:19:03.873 回答