2013-07-20 129 views
4

有沒有將錯誤消息寫入日誌文件並將其打印在終端屏幕上的方法?將stderr重定向到C中的文件和標準輸出

我試過如下:

dup2(fileno(pFile), STDERR_FILENO); /* redirect stderr to file */ 

會被重定向標準錯誤到文件中。但是,它會將錯誤消息寫入文件,但不會在屏幕上顯示它們。

這樣做可以不讀取和複製stderr的內容到文件?

注:我想不要調用shell(system,popen)。我確實看到tee命令的執行coreutils。它將標準流複製到文件。

+0

您可以嘗試「尾巴」在屏幕上查看您的輸出文件。這是最簡單的解決方案。 –

+0

@OrcunC我怎麼知道有多少行尾? – PALEN

+0

你不必知道行數。它總是顯示最後n個行數。如果你正在尋找一個特定的模式,你可以很容易地結合尾部和grep以及一個強大的日誌查看器。 –

回答

4

你有「手」來複制數據,將其發送到兩個地方,儘管它可以進行與Linux特有的T恤和拼接系統調用會更有效(注意發球系統調用不tee命令, http://blog.superpat.com/2010/07/08/a-cup-of-tee-and-a-splice-of-cake/

這聽起來像你可能知道如何做到這一點,只是希望不要,但對其他人來說,該解決方案可以是這樣的:

DUP2原來的標準錯誤(通常是終端)向新文件描述符來保存它。然後用管道()製作一個管道。 dup2將管道的寫入結束寫入fd 2.關閉原始寫入結束fd。現在你的stderr是一個管道。啓動線程或進程。在此線程中,將管道讀取端的數據複製到您保存的文件和原始stderr中。當線程或進程通過EOF讀取管道時,關閉它並退出。

popen(「tee」)解決方案是相同的,只不過它創建了一個額外的shell進程(並且您必須正確引用傳遞給shell的文件名,以防其中存在特殊字符時......請務必使用大於符號,空格和引號標記來測試奇怪的文件名......)。如果使用popen,我認爲你也可能有一個(化妝品?)問題,你不能pclose(),因爲你的stderr將停止工作,所以你將永遠留下一個額外的fd打開,並不會等待孩子。

如果你使用的是像GLib這樣的東西,它有一個g_spawn_async函數系列,可以用來在沒有shell的情況下產生tee命令。否則,你將不得不手動執行fork/exec的東西來避免shell;你可以執行tee命令,或者你可以fork但不是exec - 只需在fork完成stderr複製之後有子代碼,不要依賴tee命令。或者,您可以使用線程而不是進程。

如果使用fork,可以在gspawn.c中找到源代碼有用;在任何複雜的程序中,例如FD_CLOEXEC並不是Unix上的默認值,這很容易讓孩子繼承造成問題的描述符。 避免殭屍進程並處理所有錯誤和等等也是很煩人的。

無論如何,是的,它是比預期更多的代碼,但是在coreutils和gspawn.c的tee源碼之間,你可能有大部分可用於複製。

+0

非常感謝。此外,這是類似的帖子:http://stackoverflow.com/questions/3661070/writing-to-both-stdout-a-file。但是,在這種情況下,您的答案是解決我的需求。 – PALEN

-1

使用管道連接到tee命令。

pFile = popen("tee logfile", "w"); 
dup2(fileno(pFile), STDERR_FILENO); 
+0

如果可能,我不想調用shell ... – PALEN

+3

唯一的選擇是將所有錯誤消息寫入'pFile'和'stderr'。沒有內置的方式一次寫入兩個目的地。 – Barmar

相關問題