簡體   English   中英

可以在bash中同步進程重定向嗎?

[英]Can process redirection be synchronised in bash?

我有以下使用gcc -lstdc++ main.cpp -o main.out編譯的C ++程序。

#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main(int argc, char** argv) {
    cerr << "Error 1" << endl;
    cout << "Ok "  << endl;
    cerr << "Wowza... that's bad..."  << endl;
    cerr << "Caused by X.";
    cout << "All good in the end." << endl;

    return 0;
};

我還有一個bash腳本,如下所示,它的主要目的是在STDOUT前面加上“ SUCCESS:”,在STDERR前面加上“ ERROR:”。

./main.out > >(sed "s/^/SUCCESS: /g" >> main.log) 2> >(sed "s/^/ERROR  : /g" >> main.log)

如果我選擇cat main.log ,結果為:

ERROR  : Error 1
ERROR  : Wowza... that's bad...
ERROR  : Caused by X.
SUCCESS: Ok 
SUCCESS: All good in the end.

如您所見,發送給STDERR的字符串都出現在發送給STDOUT的字符串之前。

  1. 為什么會發生以上情況? 例如,bash是否會評估從右到左的所有流程替換?
  2. 有沒有什么方法可以使它們同步,以便字符串的順序是在C ++示例程序中定義的?

困擾您的行為是glibc的行為。 在Linux中,與glibc鏈接的程序(幾乎都是這些程序) 根據stdout和stderr的重定向位置更改其輸出緩沖模式 如果它們連接到TTY,則它們是行緩沖的。 如果將它們重定向到文件,管道或其他非TTY設備,則glibc會將它們切換到完全緩沖模式。 在完全緩沖模式下,僅每4KB左右刷新一次輸出。

在您的命令行中,這會同時影響main.outsed 添加>2>重定向時, main.out的stdout和stderr被完全緩沖。 這兩個sed的stdout流已完全緩沖,因為它們被重定向到main.log

您可以使用stdbuf覆蓋此行為。 stdbuf運行帶有stdbuf輸入和輸出緩沖的命令。 它適用於大多數程序。

如果將stdbuf替代添加到這三個命令中的每一個,則可以使它們交錯輸出。 那是個好消息。

$ rm main.log; stdbuf -oL -eL ./main.out > >(stdbuf -oL sed "s/^/SUCCESS: /g" >> main.log) 2> >(stdbuf -oL sed "s/^/ERROR  : /g" >> main.log); cat main.log
ERROR  : Error 1
ERROR  : Wowza... that's bad...
SUCCESS: Ok 
SUCCESS: All good in the end.
ERROR  : Caused by X.

$ rm main.log; stdbuf -oL -eL ./main.out > >(stdbuf -oL sed "s/^/SUCCESS: /g" >> main.log) 2> >(stdbuf -oL sed "s/^/ERROR  : /g" >> main.log); cat main.log
SUCCESS: Ok 
SUCCESS: All good in the end.
ERROR  : Error 1
ERROR  : Wowza... that's bad...
ERROR  : Caused by X.

$ rm main.log; stdbuf -oL -eL ./main.out > >(stdbuf -oL sed "s/^/SUCCESS: /g" >> main.log) 2> >(stdbuf -oL sed "s/^/ERROR  : /g" >> main.log); cat main.log
SUCCESS: Ok 
ERROR  : Error 1
SUCCESS: All good in the end.
ERROR  : Wowza... that's bad...
ERROR  : Caused by X.

壞消息是行的順序是不可預測的。 仍然不能保證輸出將按照程序編寫的順序進行。

原因是,從根本上講,您有比賽條件 您的程序和兩個sed命令是三個獨立的進程。 沒有辦法保證它們將以一定的順序運行,當您的程序向stdout輸出一條代碼時,Linux會將控制切換到適當的sed進程,然后再切換回您的程序。

Linux可以允許您的程序寫入其所有輸出,然后將控制切換到任一sed進程。 它可以交錯兩個sed進程。 它可以執行它喜歡的上下文切換。

更不用說,在多核或多處理器系統上,進程可以完全同時運行。 這是一場真正的比賽。 哪個sed運行最快,將首先輸出。

同步處理,您必須擺脫多個sed進程。 而是從兩個流中讀取一個進程。 這是一個更復雜的設計。 您將需要兩個輸入描述符,而不僅僅是一個。 您需要以某種方式select()並僅在有可用輸入時從中讀取。 這種多路復用需要一些高級Shell腳本。 您最好使用另一種語言來執行此操作。

我可以相信我可以通過示范自己回答1。

正如我所假設的,過程替換從右到左發生。

例如,執行./main.out 2> >(sed "s/^/ERROR : /g" >> main.log) > >(sed "s/^/SUCCESS: /g" >> main.log) ; cat main.log ./main.out 2> >(sed "s/^/ERROR : /g" >> main.log) > >(sed "s/^/SUCCESS: /g" >> main.log) ; cat main.log在STDERR消息之前產生所有STDOUT消息:

SUCCESS: Ok 
SUCCESS: All good in the end.
ERROR  : Error 1
ERROR  : Wowza... that's bad...
ERROR  : Caused by X.

暫無
暫無

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

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