从最后一个管道(stdin)获取退出代码

Posted

技术标签:

【中文标题】从最后一个管道(stdin)获取退出代码【英文标题】:Get exit code from last pipe (stdin) 【发布时间】:2015-08-04 09:42:33 【问题描述】:

我希望能够创建一个 bash 函数,该函数可以在管道之前读取命令的退出代码。我不确定是否可以访问它。

echo "1" | grep 2 返回 1 状态码 echo "1" | grep 1 返回 0 状态码

现在我想添加第三个命令来读取状态,用管道:

echo "1" | grep 2 | echo $? 将回显“0”,即使状态码为 1。

我知道我可以使用echo "1" | grep 2 && echo "0" || echo "1",但我更喜欢使用管道来编写它。

他们是否仍然这样做(如果它可以在大多数 shell 上工作,例如 bash、sh 和 zsh,那就更好了)

【问题讨论】:

为什么要使用管道? echo "1" | grep 2;echo $? 可以正常工作。 因为我可能还需要来自标准输入的内容。但是,我更喜欢您的解决方案而不是 @mattinbits 的解决方案 听起来像是 XY 问题。为什么需要管道内部的状态? 就像tee 获取标准输入并将其放入文件并将其传递给下一个命令,我希望能够获得状态并将所有内容传递给下一个命令。这样我就可以做echo "1" | debug | long | command | here,这样我现在就可以调试管道的状态,而不必编写多行(这样可以重复)。这有意义吗? 当我在 bash 中运行一些命令时,我主要使用 debug 函数,所以如果我能在一行中完成,我会更喜欢。 【参考方案1】:

您必须在管道的下一阶段之前获得退出状态。类似的东西

exec 3> debug.txt
 echo "1"; echo "$?" >&3;  | long | command | here

您不能(轻松)将其封装在一个函数中,因为它需要传递一个正确引用的字符串并通过eval 执行它:

debug () 
    eval "$@"
    echo $? >&3


# It looks easy in this example, but it won't take long to find
# an example that breaks it.
debug echo 1 | long | command | here

您必须将退出状态写入不同的文件描述符,否则会干扰发送到管道中下一个命令的输出。

【讨论】:

【参考方案2】:

在 bash 中,您可以使用 PIPESTATUS 变量来做到这一点

echo "1" | grep 1
echo $PIPESTATUS[0] # returns 0
echo "1" | grep 2
echo $PIPESTATUS[0] # returns 0
echo "1" | grep 2
echo $PIPESTATUS[1] # returns 1

【讨论】:

最后一个命令不在管道内。 $? 会更好,因为我想检索最后一个状态码,而不是第 n 个 @edi9999 把它放在命令里然后echo "1" | grep 2 | echo $PIPESTATUS[1] 是的,但如果我有三个命令而不是两个,它就行不通了:例如echo "1" | sed | grep 2 | echo $PIPESTATUS[1] 如果它们是当前管道之后的管道,也应该可以使用,如下所示:echo "1" | sed | grep 2 | echo $PIPESTATUS[1] | echo "3" $PIPESTATUS 获取最后一个命令的结果,而不是当前命令的结果。测试它:echo "1" \n echo "ls" | grep "ls" | echo $PIPESTATUS[$#PIPESTATUS[@]-2] 返回-bash: PIPESTATUS: bad array subscript

以上是关于从最后一个管道(stdin)获取退出代码的主要内容,如果未能解决你的问题,请参考以下文章

使用管道从 STDIN 读取分叉进程的问题

有没有办法获取早期管道 Scala 进程 (#|) 的退出代码?

从命名管道捕获非零退出代码

在 Perl 中从 STDIN 捕获退出状态

如果任何命令失败,则在最后以非零代码退出 shell 脚本

如何在 getline 管道中获取命令的退出状态?