簡體   English   中英

當一個程序在鏈中失敗時如何停止重定向標准輸出?

[英]How to stop redirecting stdout when one program fails in the chain?

在正常情況下,這將輸出 file.out

$ program1 | program2 | program3 > file.out

但是,如果發生了什么program1失敗? 發生的情況是鏈的其余部分仍然會觸發並創建文件

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

我不希望文件出現。

還有另一篇關於此的 SO 文章建議添加 OR 子句,如下所示:

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

這不起作用。 第二個命令觸發並算作成功。

同一篇 SO 文章還建議使用雙與號,如下所示:

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

這完全行不通。 在我的例子中 program2 期待來自 stdout 的輸出,所以這個鏈最終掛了,因為鏈沒有停止。 你可以通過一個簡單的例子來了解它是如何工作的:

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

它不是重定向輸出。

但是,更糟糕的是,當事情愉快時,它也不起作用。

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

在這種情況下,file.out 被創建並且它是空白的。 哦哦。


我接受了下面的答案。 調用set -o pipefail是我需要的提示。 在我的實際情況中,我使用的是 Makefile。 為了使它在 Makefile 中工作,我將它添加到文件的頂部

SHELL=/bin/bash

然后到我的目標:

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

當 bash 執行program1 | program2 | program3 > file.out program1 | program2 | program3 > file.out program1 | program2 | program3 > file.out ,它在 program1 啟動之前創建file.out 如果你想確保它永遠不會被創建,你需要緩沖輸出(在內存中或在臨時文件中)。 我發現最干凈的語法是這樣的:

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

或(這有不同的語義,忽略返回值。根據您的用例,這可能是可以接受的):

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

如果你可以創建文件然后刪除它,你可以這樣做

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

如果您不想使用 pipefail(例如,因為您希望腳本可移植),您可以執行以下操作:

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

以上是最接近你想要的; 如果您打開pipefail選項,它將起作用。 喜歡

$ set -o pipefail
$ false | echo foo > file || rm -f file
$ ls file
ls: cannot access 'file': No such file or directory

關於管道的退出狀態,以及pipefail的影響,手冊說

管道的返回狀態是最后一個命令的退出狀態,除非啟用了 pipefail 選項。 如果啟用了 pipefail,管道的返回狀態是最后一個(最右邊)命令的值,以非零狀態退出,如果所有命令都成功退出,則為零。

將您的命令包裝在函數中,您可以添加任何您想要的錯誤處理:

f_program1()
{
  program1 || pkill -f program2
}

f_program2()
{
  program2 || pkill -f program3
}

f_program3()
{
  program3
}

f_program1 | f_program2 | f_program3 > file.out

我不確定pkill是你最好的錯誤處理策略,所以把它當作一個占位符,因為函數可以讓你的麻煩消失。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM