[英]Strange redirection behaviour allowing output truncation
我們有一個構建腳本,可以為多種電路板類型構建嵌入式系統,並且以一種方式捕獲輸出時,它似乎可以正常工作。 另一種方法是,它部分通過輸出,然后在繼續之前截斷文件。
工作方式:
time ( cd ~ ; builder.sh 2>&1 | tee ~/builder.out )
和似乎截斷的方式:
time ( cd ~ ; builder.sh > ~/builder.out 2>&1 )
截斷似乎發生在非常特定的位置,截斷后文件的第一行始終是qmake
DEFAULT_INCDIRS=...
它是在過程中的特定點而不是在文件達到特定大小時,這一事實似乎表明它不是執行截斷的外部文件檢查器。
無論如何,如果腳本被刪除,腳本將繼續寫入已刪除文件的索引節點,直到關閉為止,然后它將刪除該索引節點。
實際發生的情況是該文件似乎已被截斷,然后從頭開始繼續寫入。 但是我知道,如果沒有程序實際上無法訪問文件句柄本身,就無法做到這一點。
在以上兩種情況下,構建器腳本實際上都不知道其輸出文件,它只是將輸出消息和錯誤消息都寫到stdout
並讓Shell重定向來處理它。
所以我的問題是:在文件I / O的UNIX模型中有沒有辦法做到這一點(例如,從C文件API調用)? 換句話說,當通過重定向設置了要寫入的文件時,是否可以截斷該文件? tee
為什么起作用? 是什么阻止它被截斷?
所以,是的,正如您已經注意到的,顯然有人在stdout
上調用了lseek()
或ftruncate()
。
要追蹤罪犯, strace -f
當然會有所幫助。 當做這樣奇特的事情時,您可能需要做strace -f sh -c 'build.sh 2>&1 | cat > output' > log 2>&1
strace -f sh -c 'build.sh 2>&1 | cat > output' > log 2>&1
因為它也會很高興地破壞您的strace輸出。
有了日志后,找到對lseek(1,
, lseek(2,
, ftruncate(1,
,或ftruncate(2,
的調用)。從那里,向后搜索到前一個exec
,您應該知道。
cdrecord
是一個可以正常使用stdout
游戲的程序,其中至少有一些版本希望將CD刻錄機輸出到標准輸出中。
好的,事實證明程序可以尋求標准輸出(盡管我懷疑這樣做的程序是否合理)。
以下程序說明了這一點:
#include <stdio.h>
int main(void){
for (int i = 3; i > 0; --i) {
//rewind(stdout);
printf("Hello, world %d !\n", i);
}
return 0;
}
運行此捕獲輸出,您將得到一個包含以下內容的文件:
Hello, world 3 !
Hello, world 2 !
Hello, world 1 !
但是,如果取消注釋rewind
行,則只會在輸出文件中以最后一行結束。
有趣的是,由於我無法控制截斷stdout
的程序,因此對於“貓的無用使用”獎,這實際上可能是有用的用貓。 代替執行:
myprog >outfile 2>&1
並讓myProg
截斷文件,我可以改為:
myprog 2>&1 | cat >outfile
並且管道將保護cat
輸出文件不被截斷。
就實際問題而言,似乎出於某種原因, qt5base
( buildroot
一部分)正在使用輸出文件句柄播放某種qt5base
。 由於沒有時間追逐buildroot(或創建補丁文件)以使其正確修復,因此我們使用上述cat
方法解決了該問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.