如何获取倒数第二个命令的退出状态?

7
我想在一行命令中运行两个命令,并输出第一个命令的退出状态。就像这样:
cmd1; cmd2 && echo $?-1

它应该输出cmd1的退出状态。

你在尝试做什么,顺便说一下 echo $?-1 - Inian
3个回答

10

就像其他随着时间更新其状态的全局变量一样(例如C语言中的errno),如果您想引用旧值,则需要提前存储它。

cmd1; cmd1_retval=$?; cmd2 && echo "$cmd1_retval"

顺便说一下,这个地方不同的是在流水线中:

cmd1 | cmd2 | cmd3
echo "${PIPESTATUS[$(( ${#PIPESTATUS[@]} - 2 ))]}"

这是因为在管道中,所有组件都会同时运行,默认情况下退出状态是最后一个组件的状态。然而,在bash中,所有组件的退出状态都存储在PIPESTATUS数组中;${#PIPESTATUS[@]}获取此数组的长度,从中减去两个(一个是0基索引和1基索引之间的差异,另一个是从最后一项到倒数第二项),就可以得到前面管道中倒数第二个组件的状态。


如果 cmd2 失败了,这段代码还会输出退出状态吗? - Eric Renouf
1
@EricRenouf,这并不是我的意思,但是根据提问者在问题中的代码使用 &&,他们似乎想要这样的结果。 - Charles Duffy
一个原因是因为他们承认不知道如何做,但同意你的代码与OP的示例代码保持一致。 - Eric Renouf

2
cmd1; status=$?; cmd2 && echo $status

6
大写字母的变量名称用于具有对shell或操作系统有意义的变量,而小写字母的变量名称保证不会干扰系统操作;请参见http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html的第四段。 - Charles Duffy

0
如果您有以下两个命令,其中您正在检查第一个命令的版本以查看是否安装了正确的命令版本:
#!/usr/bin/env bash

set -e

cmd1="my_command version"
cmd2="sleep 1"
exit_code=$(${cmd1}; status=$?; ${cmd2} && echo $status)
printf "_${exit_code}_"

if [[ "_${exit_code}_" == "_0_" && "$(my_command version)" =~ " 1." ]]; then
   my_command
fi

如果versionmy_command的有效选项或命令,则输出可能如下,其中my_command 1.0.0my_command version的输出,0是最后的退出代码。请注意,我已经用_将值括起来,只是为了更清楚地表达。
_my_command 1.0.0
0_

这将无法满足if语句的第一个条件。

但是,如果当前安装的my_command版本不同,并且仅支持使用选项--version,因此使用my_command version是无效的,则输出可能如下:

_1_

为了解决这个问题,我只需使用last_char=${exit_code: -1}获取最后一个字符的退出代码,并将if语句的第一个条件更改为"_${last_char}_" == "_0_"
#!/usr/bin/env bash

set -e

cmd1="my_command version"
cmd2="sleep 1"
exit_code=$(${cmd1}; status=$?; ${cmd2} && echo $status)
last_char=${exit_code: -1}
printf "_${last_char}_"

if [[ "_${last_char}_" == "_0_" && "$(my_command version)" =~ " 1." ]]; then
   my_command
fi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接