我正在使用(閉源)供應商特定的建造工具(Microsemi Designer,一種 FPGA 佈局工具)。我從 shell 腳本呼叫它(高度簡化):
... # Setup
/opt/.../designer SCRIPT:my_script.tcl |tee build.log
... # Postprocessing
問題是:即使designer
進程終止後,tee
進程仍繼續執行,因此腳本不會繼續。
據我了解,這是因為designer
生成了一個長期存在的守護進程 ,
windu_scmd50
並且該守護程序不會關閉其標準輸出(它繼承自designer
)。因此,tee
正在等待其標準輸入(連接到管道)上的 EOF,但它永遠不會到來。
有證據表明這是問題的原因:
ps
顯示 tee 進程仍在運行,但設計器進程未運行。- 當我終止
windu_scmd50
進程時,tee
立即終止並且腳本繼續(但我無法在生產中執行此操作)。 - 如果我不透過管道將
designer
to的輸出tee
(或其他任何東西;cat
代替 of發生同樣的事情tee
),腳本不會停止。 - 如果我
designer
從 Jenkins 運行(不將輸出通過管道傳輸到檔案),Jenkins 會通知我“進程洩漏的檔案描述符”,連結到 這個幫助頁面(顯然,詹金斯明確處理了這種情況)。
所以:如何確保tee
進程在進程終止時(或之後不久)終止designer
?
我考慮過的一些方法:
- 是否可以重定向正在運行的進程的標準輸出?
- 是否有一個工具可以取代 shell 管道來偵測進程的終止
designer
?
一些不可能的方法:
- 我不能忽視這個
designer
過程的輸出;我需要將其寫入日誌檔案。 - 我無法終止該
windu_scmd50
進程,因為它可能被電腦上的其他進程使用。 - 上描述的解決方法詹金斯幫助頁面似乎不適用,因為它們也會使 的輸出靜音
designer
。 - 我無法修改工具安裝以
windu_scmd50
用包裝器取代可執行檔。
更多注意事項:
- 記錄該過程的輸出
windu_scmd50
會很好,但這不是必需的。但是,我確實需要記錄設計器流程的輸出。 - 實際上,在
designer
和之間還有另一個過濾器tee
,它會添加時間戳記 (designer ... |ts -s |tee build.log
) - 使用
bash
特定功能是可以接受的;相容性sh
不是必需的
這是演示該問題的最小範例 ( test.sh
):
#!/bin/bash
echo "Start"
sleep 10 & # Background process that does not close stdout
echo "End"
直接呼叫此腳本 ( ./test.sh
) 會列印「Start」和「End」並立即完成。將輸出透過管道傳輸到另一個進程 ( ./test.sh |cat
) 會立即列印“Start”和“End”,但在完成之前會暫停 10 秒。
答案1
一個非常簡單的解決方法是在進程終止後向流注入一條訊息designer
。cat
前面的類似過濾器應該tee
在遇到訊息時退出。
它會是這樣的:
{ /opt/.../designer SCRIPT:my_script.tcl; echo message; } \
| sed -n '/^message$/q;p' | tee build.log
筆記:
如果
designer
(或繼承其標準輸出的任何內容)列印該訊息,sed
則將提前退出。選擇一個sTr1ng_Unlik3ly t0-Be enCOUnTered_in vvhat designer PRinT5
。 ASCII EOT 字元(八進位 004)可能是不錯的選擇:
{ …; printf '\004\n'; } | sed -n "/^$(printf '\004')\$/q;p" | …
能夠處理的事情是有限的
sed
。看這個答案關於grep
,與 類似sed
。^message$
匹配僅包含的整行message
。這假設進程的輸出(如果有)designer
以換行符號結束(即最後一行已完成;請參閱線與不完整的線);只有這樣,message
才會在自己的行列中。如果designer
肯定會產生不完整的行,那麼您想要sed -n '/message$/{s/message$//;p;q};p'
.如果可以是任何一種方式那麼你想要的sed -n '/^message$/q;/message$/{s/message$//;p;q};p'
。請注意,不完整的行將designer
變成完整的行。的非沉默後代
designer
可能會幹擾:- 它們可能會導致
message
出現在中線(即使它們嘗試輸出完整的行)。對我們來說,sed
這就像是designer
生成了一條不完整的線。 - 如果您選擇的訊息很長,那麼它可能會與其他資料交錯出現在管道中(請參閱這個答案和
PIPE_BUF
這裡)。在這種情況下我們sed
根本不會檢測到它。
- 它們可能會導致