使用“ bash -e”时,如何获取子外壳的输出和退出值?


70

考虑以下代码

external-scope.sh

#!/bin/bash
set -e
source inner-scope.sh
echo $(inner)
echo "I thought I would've died :("

inner-scope.sh

#!/bin/bash
function inner() { echo "winner"; return 1; }

outer-scope.sh通话inner()失败时,我试图退出。由于$()调用了子外壳程序,因此不会发生这种情况。

在保留函数可能会以非零退出代码退出的事实的同时,如何获取函数的输出呢?

Answers:


102

$()保留退出状态;您只需要在没有自己状态的语句(例如赋值)中使用它。

输出= $(内部)

此后,$?将包含的退出状态inner,您可以对其进行各种检查:

output=$(inner) || exit $?
echo $output

要么:

if ! output=$(inner); then
    exit $?
fi
echo $output

要么:

if output=$(inner); then
    echo $output
else
    exit $?
fi

(注意:exit不带参数的裸露等效于exit $?–即,它以最后一条命令的退出状态退出。我仅出于清晰起见使用第二种形式。)


另外,记录:source在这种情况下是完全无关的。您只需inner()outer-scope.sh文件中进行定义即可获得相同的结果。


即使$,为什么会这样呢?包含$()的退出状态,脚本不会自动退出(假设已设置-e)?编辑:没关系,我想你已经回答了我的问题,谢谢!
jabalsad 2011年

我不确定。(我没有测试以上任何内容。)但是,-e有一些限制,所有限制都在bash的联机帮助页中进行了解释;同样,如果您询问的是echo $(),则可能是因为当行(该echo命令)具有自己的退出代码(通常为0)时,会忽略子外壳的退出代码。
grawity

1
嗯,当我打字时if ! $(exit 1) ; then echo $?; fi,我得到了0if如果您需要保留该退出值,则不确定该走的路。
罗恩·伯克

@grawity-这与Dash兼容吗?我正在尝试解决一些令人讨厌的Autoconf行为(即,当Sun或IBM的编译器向终端打印非法选项时,Autoconf报告成功)。
jww

3
if ! output=$(inner); then exit $?; fi将以0的返回码退出,因为$?它将给出的返回码为!而不是的返回码inner。您可以用达到预期的行为,if output=$(inner); then : ; else exit $?; fi但这显然更为冗长
SJL

26

参见BashFAQ / 002

如果您同时需要(输出和退出状态):

output=$(command)
status=$? 

特例

请注意有关函数局部变量的棘手情况,请比较以下代码:

f() { local    v=$(echo data; false); echo output:$v, status:$?; }
g() { local v; v=$(echo data; false); echo output:$v, status:$?; }

我们会得到:

$ f     # fooled by 'local' with inline initialization
output:data, status:0

$ g     # a good one
output:data, status:1

为什么?

当子外壳程序的输出用于初始化local变量时,退出状态不再是子外壳程序的退出状态,而是命令的退出状态,最有可能是。local 0

另请参阅https://stackoverflow.com/a/4421282/537554


3
虽然这并未真正回答问题,但今天对我很有用,所以+1。
fourpastmidnight

1
bash命令的退出状态始终是最后执行的命令的退出状态。当我们在强类型语言中花费大量时间时,很容易忘记“ local”不是类型说明符,而只是另一个命令。感谢您在这里重申这一点,今天对我有所帮助。
markeissler's

2
哇,我刚才遇到了这个确切的问题,您已经解决了。谢谢!
krb686

4
#!/bin/bash
set -e
source inner-scope.sh
foo=$(inner)
echo $foo
echo "I thought I would've died :("

通过添加echo,子外壳程序不会独立存在(不会单独检查)并且不会中止。作业可以解决此问题。

您也可以执行此操作,然后将输出重定向到文件,以供以后处理。

tmpfile=$( mktemp )
inner > $tmpfile
cat $tmpfile
rm $tmpfile

当然,$ tmpfile在第二个变体中仍然存在...
丹尼尔·贝克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.