2016-10-04 240 views
2

我需要能夠重定向輸出到一個文件,並檢查KSH腳本的返回代碼(不能使用pipestatus或pipefail),我找到了一個解決方案,但我不確定文件描述符4的意義是什麼,有人可以解釋一下嗎?輸出文件描述符重定向

{ 
rc=$(
{ 
    { 
    . somescript.sh 2>&1 
    echo "$?" >&3 
    } | tee -a somefile.txt 
} 3>&1 >&4 4>&- 
) 
} 4>&1 

echo "${rc}" 

回答

2

rc=$(...)意味着該返回碼將是任何由(...)內的代碼印刷在文件描述符(FD)1。所以,不知何故,somescript.sh輸出必須被移出fd 1,然後再回來。 echo行輸出somescript.sh的返回碼爲fd 3。然後,3>&1將保存的返回碼發送到fd 1,其中$(...)預計它。然而,這意味着舊的fd 1(從{somescript 2>&1 } | tee)沒有任何可去的地方。所以舊的fd 1被重定向到fd 4>&4(並且由於輸入側不會被使用,所以輸入側被關閉了4>&-)。然後,一旦$(...)結束,最後的4>&1somescript|tee的輸出放回到其他程序期望它的fd 1處。

Whe!

沒有>&4somescript.sh輸出和echo "$?"輸出將上因爲3>&1的FD 1混合。因此,fd 4是在使用fd 1來執行返回碼期間的實際輸出somescript.sh的等待筆。

+0

我一直認爲$(...)是從stdout讀取的,這也是fd 1通常指向的內容,但是如果它從fd 1讀取,那麼這會很有意義。謝謝。 – dood

+0

fd 1不「指向」標準輸出;它*是*標準輸出。 – chepner

+0

@chepner啊好的,謝謝你的澄清,然後通常stdout指向終端。 – dood

1

如果你願意使用命名管道,可以與所有的文件描述符角力分配:

mkfifo p 
tee -a somefile.txt < p & 
. somescript.sh > p 
rc=$? 

在這裏,我們在後臺運行tee,讓它從命名管道讀取其輸入p。一旦該作業開始,我們就會獲取腳本並將其輸出重定向到命名管道。腳本完成後,您可以使用普通的賦值語句將其退出狀態保存到rc。這也將關閉管道的殼端,這將導致另一端也關閉,並允許退出tee

+0

如果你用fd'1'開始指向終端,當'somescript.sh'開始在'p'上產生輸出時,'tee ...'會導致'tee'以'SIGTTOU'結束? – cxw

+0

理論上,是的,但'ksh'應該覆蓋'SIGTTOU'的默認行爲,以允許'tee'直接寫入終端。 (說實話,我不得不查看'SIGTTOU'是什麼,因爲當我測試這個時,我沒有注意到任何問題。) – chepner

+0

[「在上面的代碼中注意錯誤;我只證明它是正確的,沒有嘗試過。「](http://staff.science.uva.nl/~peter/knuthnote.pdf)* Knuth * :)謝謝! – cxw