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

Posted

技术标签:

【中文标题】从命名管道捕获非零退出代码【英文标题】:Capture non-zero exit code from named pipe 【发布时间】:2018-11-23 17:02:51 【问题描述】:

即使发送到命名管道的进程失败,以下玩具脚本 (tmp.sh) 也会以代码 0 退出。如何从命名管道中捕获非零退出代码?或者更笼统地说,某事出了问题?

#!/bin/bash

set -eo pipefail

mkfifo mypipe
FOOBAR > mypipe &

cat mypipe

运行并检查退出代码:

bash tmp.sh
tmp.sh: line 6: FOOBAR: command not found

echo $? # <- Exit code is 0 despite the "command not found"!

【问题讨论】:

【参考方案1】:

您需要捕获后台进程的进程 ID 和 wait 以设置正确的退出状态:

#!/bin/bash
set -eo pipefail

rm -f mypipe
mkfifo mypipe

FOOBAR > mypipe &
# store process id of above process into pid
pid=$!

cat mypipe

# wait for background process to complete
wait $pid

现在当你运行它时:

bash tmp.sh
tmp.sh: line 6: FOOBAR: command not found
echo $?
127

【讨论】:

如果不是脚本中的最后一个命令,您需要显式捕获/处理来自wait 的返回。你可以设置一个陷阱。 如果等待是最后一个推荐,那么退出状态将是等待返回的任何内容【参考方案2】:

如果您需要能够捕捉错误并应用特定行为,陷阱可以成为您的朋友。这段代码会自己打印,所以我只是在这里发布一个运行:

$: tst
+ trap 'x=$?; echo "$x@$0:$LINENO"; exit $x' err
+ rm -f mypipe
+ mkfifo mypipe
+ pid=6404
+ cat mypipe
+ cat ./tst
#! /bin/env bash

set -x

trap 'x=$?; echo "$x@$0:$LINENO"; exit $x' err
#set -eo pipefail

rm -f mypipe
mkfifo mypipe

cat $0 >mypipe &
pid=$!
cat mypipe
wait $pid

fubar >mypipe &
pid=$!
cat mypipe
wait $pid

echo done

+ wait 6404
+ pid=7884
+ cat mypipe
+ fubar
./tst: line 16: fubar: command not found
+ wait 7884
++ x=127
++ echo 127@./tst:19
127@./tst:19

注意trap 'x=$?; echo "$x@$0:$LINENO"; exit $x' err 行。 它将 x 设置为最后一个错误代码,这将是触发它的任何内容。然后它打印代码、文件名和它当前正在执行的行号(在陷阱之前)并以错误代码退出程序。这实际上在wait 上触发。它会导致它在继续底部的回声之前退出。

不管有没有set -eo pipefail,它都可以工作。

【讨论】:

以上是关于从命名管道捕获非零退出代码的主要内容,如果未能解决你的问题,请参考以下文章

检测命名管道的关闭

如何等待 n 秒以打开命名管道?

命名管道 232 管道正在关闭

使用命名管道时如何防止死锁?

从命名管道读取不会给出任何输出并无限期地阻塞代码

没有从控制台发出命令的 C# 命名管道?