2016-02-04 84 views
2

我有一个管道,说a | b如果遇到问题,我想停止整个管道。崩溃停止bash管道

'退出并退出= 1不会经常这样做'b不关心返回代码。

例如

echo 1 | grep 0 | echo $? < - 这表明grep退出= 1 ,但是 echo 1 | grep 0 | wc < --- wc对grep的退出没有影响

如果我将管道作为拥有进程的子进程运行,任何管道进程都可能会终止拥有进程。但是这看起来有点笨拙 - 但它会打败整个管道。

+0

很难准确地了解你在问什么,但或许这可以帮助? http://stackoverflow.com/a/19804002/2096752 – shx2

+0

也许这样? (a) if [[$? -eq 0]];然后 b $ a fi – Joda

+0

但是,运行'a完成。我想'b(以及任何后续的事情)都在进行中。此外,如果我的管道更长,比如a | b | c | d | e | f,我将不得不在每个阶段重复该逻辑。我希望管道中的任何阶段都能够阻止其他阶段。 – user1202733

回答

0

基本shell结构不可能,根本不可能在shell中。

你的第一个例子没有做你的想法。 echo不使用标准输入,因此将其放在管道的右侧从来就不是一个好主意。您所呼应的$?不是grep 0的退出值。管道中的所有命令都同时运行。在管道中的其他命令完成之前,echo已经启动,现有值为$?。它回应了你在管道之前所做的任何事情的退出价值。

# The first command is to set things up so that $? is 2 when the 
# second command is parsed. 
$ sh -c 'exit 2' 
$ echo 1|grep 0|echo $? 
2 

你的第二个例子更有趣一点。正确地说wc不受grep的退出状态的影响。管道中的所有命令都是shell的子项,因此它们的退出状态会报告给shell。 wc进程不知道有关grep进程的任何信息。它们之间的唯一通信是通过grep写入管道的数据流并通过wc从管道读取。

有些方法可以在事实之后找到所有的退出状态(shx2的注释中的链接问题有示例),但是您无法避免的基本规则是shell始终等待所有命令完。

提前退出管道有时会产生级联效应。如果管道右侧的命令在不读取管道中的所有数据的情况下退出,则该管道左侧的命令将在下次尝试写入时收到SIGPIPE信号,默认情况下终止该过程。 (需要注意的两个短语是“下次尝试写入”和“默认情况下”。如果写入过程花费很长时间在写入管道之间做其他事情,它不会立即死亡。如果它处理SIGPIPE,它将根本不会死亡。)

另一方面,当管道左侧的命令退出时,该管道右侧的命令将获得EOF,它将如果它是一个简单的命令,例如wc,在读取其输入后没有做太多的处理,会导致退出很快发生。

通过直接使用pipe(),fork()wait3(),可以构建一个管道,注意当一个孩子严重退出并立即杀死其余的孩子。这需要比shell更复杂的语言。

我试图想出一个方法来在shell中使用一系列命名管道来完成它,但我没有看到它。您可以将所有进程作为单独的作业运行,并获得其PID为$!,但wait内建的灵活性不足以说“等待此组中的任何孩子退出,并告诉我它是哪一个,以及退出状态是什么是”。

如果你愿意混淆ps和/或/proc你可以找出哪些进程已经退出(他们将成为僵尸),但是你不能区分成功退出和其他类型。

0

set -e 
set -o pipefail 

在你的文件的开头。

-e将退出上的错误和-o pipefail会产生对你每个阶段的错误代码“管道”