[英]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.