簡體   English   中英

git stderr輸出無法管道

[英]git stderr output can't pipe

我正在使用bash和zenity為git://鏈接編寫圖形URI處理程序,並且我正在使用zenity'text-info'對話框來顯示git在運行時的克隆輸出,使用FIFO管道。 這個腳本長約90行,所以我不打算在這里發帖,但這里是最重要的一行:

git clone "$1" "$target" 2>&1 | cat >> /tmp/githandler-fifo &
cat /tmp/githandler-fifo | zenity --text-info --text='Cloning git repository' &

我正在使用FIFO而不是直接管道來允許它們異步運行並允許在zenity窗口關閉時殺死git。

問題是,git輸出中出現的唯一一行是第一行:

Initialized empty Git repository in /home/delan/a/.git/

帶有計數對象等的其他行不顯示或顯示在終端上。

目前的原因

目前關於為什么這不起作用的共識似乎是cat是非阻塞的並且在第一行之后退出,只是將其傳遞給zenity而不是其他。 我的目標是強制阻止讀取,並讓zenity的文本信息對話框逐步顯示所有輸出。

git在stderr上輸出進度消息(除了“Initialized”消息之外的任何內容),但是當我嘗試將stderr管道傳輸到文件或與stdout合並時,消息就消失了。

修復嘗試1

我試圖在C,面包和bwrite中編寫cat函數的兩個阻塞版本,如下所示:

#include <stdio.h>
main(int argc, char **argv) {
    int c;
    for (;;) {
        freopen(argv[1], "r", stdin);
        while ((c = getchar()) != EOF)
            putchar(c);
    }
}

#include <stdio.h>
main(int argc, char **argv) {
    int c;
    for (;;) {
        freopen(argv[1], "w", stdout);
        while ((c = getchar()) != EOF)
            putchar(c), fputs("writing", stderr);
    }
}

它們很好地工作,因為它們阻止並且不會退出EOF,但它還沒有完全解決問題。 目前,使用一個,另一個或兩者,在理論上起作用,但在實踐中,zenity現在根本沒有顯示任何東西。

修復嘗試2

@mvds建議使用常規文件,結合tail -f而不是cat ,可以這樣做。 對這樣一個簡單的解決方案感到驚訝(謝謝!)我嘗試過但不幸的是,只有第一行出現在zenity而沒有別的。

修復嘗試3

在做了一些strace'ing並檢查git的源代碼之后,我意識到git在stderr上輸出了它的所有進度信息(任何超過“Initialized”消息的信息),以及這是第一行和我的假設,因為它是因為cat在EOF早期退出是一個巧合/錯誤的假設(git在程序結束之前不會EOF)。

情況似乎變得更加簡單,因為我不應該從原始代碼(在問題的開頭)改變任何東西,它應該工作。 然而,神秘的是,當重定向時,stderr輸出“消失” - 這只是git中發生的事情。

測試用例? 試試這個,看看你是否在文件中看到任何內容(你不會):

git clone git://anongit.freedesktop.org/xorg/proto/dri2proto 2> hurr

這違背了我對stderr和重定向的所有了解; 我甚至編寫了一個在stderr和stdout上輸出的小程序來向自己證明重定向對git不起作用。

修復嘗試4

根據JakubNarębski的回答,以及對我發送到git郵件列表的電子郵件的回復, - --progress是我需要的選項。 請注意,此選項僅在命令之后有效,而不是在clone之前。

成功!

非常感謝您的幫助。 這是固定的:

git clone "$1" "$target" --progress > /tmp/githandler-fifo 2>&1 &

我認為當輸出不是終端 (tty)時,至少有一些進度報告會被靜音。 我不確定它是否適用於您的情況,但嘗試將--progress選項傳遞給'git clone'(即使用git clone --progress <repository> )。

雖然我不知道這是不是你想要的。

首先,輸出重定向是從右到左解析的,所以

git clone "$1" "$target" 2>&1 > /tmp/githandler-fifo &

不等於

git clone "$1" "$target" > /tmp/githandler-fifo 2>&1 &

后者會將stderr重定向到stdout,然后將stdout(包括stderr)重定向到該文件。 前者將stdout重定向到文件,然后在stdout上顯示stderr。

至於管道到zenity (我不知道),我認為你可能會使命名管道過於復雜。 使用strace可以揭示你正在開火的過程的內部運作。 對於缺乏經驗的命名管道,與普通管道相比,情況更糟。

鑒於FIFO的實驗稱為'a',我認為問題在於zenity處理其輸入的方式。 如果從鍵盤輸入zenity會發生什么? (懷疑:它的行為與你想要的一樣,讀取到EOF。)但是,可能是zenity使用常規阻塞I / O處理終端輸入(tty輸入),但對所有其他設備類型使用非阻塞I / O. 非阻塞I / O適用於文件輸入; 它不太適合來自管道或FIFO等的輸入。如果它確實使用非阻塞I / O,zenity將獲得第一行輸出,然后退出循環認為它已完成,因為它的第二次讀取嘗試將指示沒有別的東西立即可用。

證明這是正在發生的事情(或不發生)將是棘手的。 我希望'桁架'或'strace'或其他系統調用監視器來跟蹤zenity正在做什么。

至於解決方法......如果假設是正確的,那么你需要說服它從終端而不是FIFO中讀取zenity,所以你可能需要裝備一個偽tty(或pty); 第一個進程將寫入pty的主端,並且您將安排zenity從pty的slave端讀取。 您可能仍然使用FIFO - 盡管它會產生一長串命令。

暫無
暫無

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

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