使用 tee 處理替換和重定向
假設您在 bash 中將命令的標準輸出重定向
cmd
到名為 的文件f.out
,並將標準錯誤重定向到f.err
,tee
用於保留控制台列印:cmd 1> >(tee f.out) 2> >(tee f.err)
然後
f.out
包含輸出和錯誤(至少在我的系統上)。現在,如果您更改重定向的順序:
cmd 2> >(tee f.err) 1> >(tee f.out)
f.out
僅包含輸出(並且f.err
僅包含兩種情況下的錯誤)。所以我的問題是雙重的:如何將 stderr 重定向到
f.out
,為什麼重定向的順序會影響結果?請注意,如果您不使用
tee
,但例如cat
,像這樣:cmd 1> >(cat>f.out) 2> >(cat>f.err)
您沒有這個問題,並且重定向的順序並不重要,正如預期的那樣,並且沒有程序替換(
cmd 1>f.out 2>f.err
)就是這種情況。
重定向的順序很重要,因為 Bash 按照它在解釋的命令中找到它們的順序應用它們。
這是故意的,這樣您就可以擁有像
> file 2>&1
預期一樣工作的習語,即讓 stderr 與 stdout 相同。這個習慣用法就像“分配file
給 stdout,然後使 stderr 等於 stdout”,這會產生預期的結果,因為當 stderr 獲得 stdout 的相同值時,stdout 的值為file
. 反過來(即2>&1 1> file
)不會產生相同的結果,因為 stdout 的值在被複製到 stderr 的值之後發生了變化。文件描述符可以被認為類似於正常變數,它們有自己的值,可以用來獲取另一個變數值的副本,如 invar1="${var2}"
,很像這樣var1
不會跟隨var2
的後續值更改,文件描述符的值也不會。它也很方便,因此您可以在同一行交換文件描述符,例如在
3>&1 1>&2 2>&3-
. 這使用 fd 3 作為臨時“幫助” fd 交換 fds 1 和 2。因此,您可以將重定向視為順序執行的指令,就像它們位於命令或腳本的兩個單獨行上一樣。
在您的特定情況下,還涉及流程替換,並且這些替換也以指定的順序執行,繼承了到目前為止表達的重定向
也就是說,將其全部覆蓋:
- 您首先將標準輸出重定向到正在執行的程序
tee f.out
;此時cmd
的標準輸出連接到tee f.out
標準輸入,根據需要- 然後將 stderr 重定向到正在執行的程序
tee f.err
;但這會根據之前表達的重定向繼承其標準輸出,即連接到tee f.out
的標準輸入因此
tee f.err
,通過無辜地輸出到其標準輸出以及 f.err 文件,將您cmd
的錯誤消息通過管道傳輸到tee f.out
標準輸入,因此標準輸入將接收所有消息,並將它們輸出到 f.out 文件以及您的終端視窗。