问题 为什么使用Bash只读变量来捕获输出无法捕获返回码$?


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

#!/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 可执行文件。但是,如果我删除 readonly 从 OUTPUT 变量,它保留错误的退出代码并检测到故障。

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

是否有一些清洁的解决方案来保存 readonly 同时仍然捕获命令/子shell的退出代码?令人失望的是,必须记住这种特殊用例,或者还原为不使用 readonly 曾...

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


3614
2017-09-26 06:30


起源

完全相同的问题 export 顺便一提。 - cdarke


答案:


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

help readonly

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

因此,您需要使用两个单独的命令:

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

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

$ echo $res
1

缺乏 进入调试器,没有办法取消设置只读变量。因此,除非您希望它在剩余的bash会话中保持不变,否则不要设置readonly变量。

变异

他们俩 readonly 命令可以组合成一个(帽子提示: Chepner):

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

在旁边

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


11
2017-09-26 06:39



为了在最佳实践中添加你的旁边, { } 周围 ${RES} 没有执行任何功能。该 [[ ]] 正在进行文本比较,以进行算术比较使用 if (( RES != 0 ))。 - cdarke
谢谢,我不知道我可以使用 readonly 后来。 - Vincas Dargis
您还可以使用相同的命令在两个变量上设置只读标志: readonly res=$? output - chepner
@chepner非常好。更新答案以显示具有单个只读命令的解决方案。 - John1024