当一个程序链中的一个程序失败时,如何停止重定向标准输出? [英] How to stop redirecting stdout when one program fails in the chain?

查看:44
本文介绍了当一个程序链中的一个程序失败时,如何停止重定向标准输出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在正常情况下,这将输出file.out

In the normal case, this would output file.out

$ program1 | program2 | program3 > file.out

但是,如果 program1 失败怎么办?发生的是,链的其余部分仍然可以触发并且文件已创建

But what happens if program1 fails? What happens is that the rest of the chain still fires and the file is created

$ false | echo worked > file.out
$ cat file.out
worked

我不想显示该文件.

还有另一篇有关此的 SO文章建议添加一个OR子句,如下所示:

There is another SO article about this that suggests adding an OR clause, like so:

$ false | echo worked > file.out || rm file.out
ls file.out
file.out  

这不起作用.第二个命令将触发并算作成功.

This doesn't work. The second command fires and counts as a success.

同一篇SO文章还建议使用双&"号,例如:

That same SO article also suggests using a double ampersand, like so:

$ program1 && program2 && program2 > file.out

那并不完全有效.在我的情况下,program2期望从stdout输出,因此该链最终挂起,因为该链没有停止.您可以通过一个简单的示例看到它的工作原理:

That doesn't work entirely. In my case program2 is expecting output from the stdout, so this chain ends up hanging because the chain is not stopping. You can see how this works with a trivial example:

$ echo something > stuff.txt
$ cat stuff.txt && false > file.out
something
$ cat file.out

它没有重定向输出.

但是,更糟糕的是,当事情变得快乐时,它也不起作用.

But, even worse, when things are happy, it doesn't work either.

$ echo something > stuff.txt
$ cat stuff.txt && true > file.out
something
$ cat file.out

在这种情况下,file.out被创建并且为空白.嗯.

In this case, file.out is created and it's blank. Uh-Oh.

我在下面接受了答案.调用 set -o pipefail 是我需要的技巧.在我的实际情况下,我使用的是Makefile.为了使它适用于Makefile,我将其添加到了文件的顶部

I accepted an answer below. Calling set -o pipefail was the tip that I needed. In my real situation, I'm using a Makefile. To adapt this to work in a Makefile, I added this to the top of the file

SHELL=/bin/bash

然后到达我的目标:

target:
    @set -o pipefail; program1 | program2 | program3 > $@

推荐答案

当bash执行 program1 |节目2 |程序3file.out ,它将在启动program1之前创建 file.out .如果要确保从不创建它,则需要对输出进行缓冲(在内存中或在临时文件中).我发现最干净的语法是这样的:

When bash executes program1 | program2 | program3 > file.out, it creates file.out before program1 is started. If you want to ensure that it is never created, you'll need to buffer the output (either in memory or in a temporary file). I find the cleanest syntax for that is something like:

if v=$( set -o pipefail; program1 | program2 | program3 ); then 
    echo "$v" > file.out
fi

或(这有不同的语义,忽略了返回值.根据您的用例,这可能是可以接受的):

or (this has different semantics, ignoring the return value. Depending on your use case, this may be acceptable):

v=$( program1 | program2 | program3 )
test -n "$v" && echo "$v" > file.out

如果您可以先创建文件然后删除它,则可以

If you're okay with creating the file and then deleting it, you can do

set -o pipefail
program1 | progam2 | program3 > file.out || rm file.out

如果您不想使用pipefail(例如,因为您希望脚本具有可移植性),则可以执行以下操作:

If you don't want to use pipefail (eg, because you want the script to be portable), you can do something like:

{ { { program1 || echo . >&3; } | { program2 || echo . >&3;} | 
{ program3 || echo . >&3; } } 3>&1 >&4 | 
if grep -q .; then exit 1; else exit 0; fi ; } 4>&1;

这篇关于当一个程序链中的一个程序失败时,如何停止重定向标准输出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆