Bash

使用 tee 處理替換和重定向

  • April 23, 2020

假設您在 bash 中將命令的標準輸出重定向cmd到名為 的文件f.out,並將標準錯誤重定向到f.errtee用於保留控制台列印:

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 的值之後發生了變化。文件描述符可以被認為類似於正常變數,它們有自己的值,可以用來獲取另一個變數值的副本,如 in var1="${var2}",很像這樣var1不會跟隨var2的後續值更改,文件描述符的值也不會。

它也很方便,因此您可以在同一行交換文件描述符,例如在3>&1 1>&2 2>&3-. 這使用 fd 3 作為臨時“幫助” fd 交換 fds 1 和 2。

因此,您可以將重定向視為順序執行的指令,就像它們位於命令或腳本的兩個單獨行上一樣。

在您的特定情況下,還涉及流程替換,並且這些替換也以指定的順序執行,繼承了到目前為止表達的重定向

也就是說,將其全部覆蓋:

  1. 您首先將標準輸出重定向到正在執行的程序tee f.out;此時cmd的標準輸出連接到tee f.out標準輸入,根據需要
  2. 然後將 stderr 重定向到正在執行的程序tee f.err;但這會根據之前表達的重定向繼承其標準輸出,即連接到tee f.out的標準輸入

因此tee f.err,通過無辜地輸出到其標準輸出以及 f.err 文件,將您cmd的錯誤消息通過管道傳輸到tee f.out標準輸入,因此標準輸入將接收所有消息,並將它們輸出到 f.out 文件以及您的終端視窗。

引用自:https://unix.stackexchange.com/questions/510298