为啥使用 Bash 只读变量捕获输出无法捕获返回码 $?

Posted

技术标签:

【中文标题】为啥使用 Bash 只读变量捕获输出无法捕获返回码 $?【英文标题】:Why using Bash readonly variable to capture output fails to capture return code $?为什么使用 Bash 只读变量捕获输出无法捕获返回码 $? 【发布时间】:2017-02-03 09:30:02 【问题描述】:

下面的示例尝试执行命令并检查它是否成功执行,同时捕获它的输出以供进一步处理:

#!/bin/bash

readonly OUTPUT=$(foo)
readonly RES=$?

if [[ $RES != 0 ]]
then
    echo "failed to execute foo"
    exit 1
else
    echo "foo success: '$OUTPUT'"
fi

它报告它是成功的,即使没有这样的foo 可执行文件。但是,如果我从 OUTPUT 变量中删除 readonly,它会保留错误的退出代码并检测到故障。

我尝试使用 readonly 作为某处推荐的“防御性编程”技术......但在这种情况下看起来它会咬自己。

是否有一些干净的解决方案来保留readonly,同时仍捕获命令/子shell 的退出代码?如果人们不得不记住这种特殊的用例,或者恢复到永远不使用readonly,那将是令人失望的......

在 Debian Wheezy 上使用 Bash 4.2.37(1)。

【问题讨论】:

顺便说一句,与export 完全相同。 【参考方案1】:

问题是readonly 是它自己的命令,它返回的退出代码是它自己的退出代码,而不是命令替换的退出代码。

来自help readonly

退出状态: 除非给出无效选项或 NAME 无效,否则返回成功。

所以,你需要使用两个单独的命令:

$ output=$(false)
$ readonly res=$?
$ readonly output

这会保存您想要的退出代码:

$ echo $res
1

缺少entering a debugger,无法取消设置只读变量。因此,不要将变量设置为只读,除非您希望它在 bash 会话的剩余时间内保持不变。

变化

两个readonly 命令可以合并为一个(帽子提示:Chepner):

$ output=$(false)
$ readonly output res=$?
$ echo $res
1

一边

最佳做法是为变量使用小写或混合大小写的名称。系统使用所有大写名称,您不想意外覆盖系统变量。

【讨论】:

补充一下最佳实践, 周围的 $RES 没有执行任何功能。 [[ ]] 正在执行文本比较,要执行算术比较,请使用 if (( RES != 0 )) 您还可以使用相同的命令在两个变量上设置只读标志:readonly res=$? output @chepner 非常好。已更新答案以显示具有单个只读命令的解决方案。

以上是关于为啥使用 Bash 只读变量捕获输出无法捕获返回码 $?的主要内容,如果未能解决你的问题,请参考以下文章

如何将curl的输出捕获到bash中的变量[重复]

在 bash 脚本中将 SSH 输出捕获为变量

如何在环境变量中捕获bash命令组(花括号)的输出

在 Java Lambda 中,为啥在捕获的变量上调用 getClass()

为啥表单提交没有捕获我在输入标签中设置的只读默认值?

为啥我无法在具有 void 返回类型的异步函数中捕获异常?