使用 3>&1 1>/dev/null 重定向時會發生什麼?
我正在玩弄文件描述符以更好地理解它們,但我無法理解以下內容。
$ grep "..." 3>&1 1>/dev/null 1 12 13 123 321 3
上面沒有在 shell 中顯示任何匹配項,這顯然是因為我正在重定向到 /dev/null。我不明白的是為什麼
3>&1
不讓它讓我仍然看到輸出,因為我在 fd 3 中製作了它的副本。我錯過了什麼?
您的重定向確實使 FD 3 成為 FD 1 的副本,因此 FD 3 將指向標準輸出,寫入它的任何內容都會(預設情況下)發送到 TTY。然後將 FD 1 重定向到
/dev/null
,因此寫入 FD 1 的任何內容都將被丟棄。因為grep
從不寫入 FD 3,所以它不會發生任何可見的事情。這些按順序發生:首先將
dup2
FD 1 的副本 ( ) 複製到 FD 3,因此 FD 3 從此指向 FD 1 目前指向的位置,其次 FD 1 被指向 的指針替換/dev/null
。最終結果如下圖所示:
標準錯誤(粉紅色,FD 2)和 FD 3 到 TTY,標準輸出到
/dev/null
. FD 3 仍然指向 TTY,因為這是 FD 1 在複製時指向的位置。但是,該grep
命令不會嘗試向 FD 3 寫入任何內容,因此該副本永遠不會得到任何使用。“複製”是定向的:
3>&1
處理後,寫入 FD 3 的任何內容都將轉到 FD 1 在處理時指向的位置。它不會“保留”除此之外的任何內容:如果您隨後重定向 FD 1,則寫入其中的任何內容都會轉到新位置。您所做的將保留到 FD 1 的原始目的地,以防您以後想使用它。grep
影響標準輸出最終位置的唯一重定向是1>...
明確討論其去向的重定向。如果要寫入 FD 3,它將按預期出現在終端中
grep
*。*因為它只正常輸出到FD 1,所以它的所有實際輸出都被丟棄了。如果需要,我們可以將 grep 輸出到 FD 3:
( grep "..." >&3 )
這將採用 FD 1 上的正常輸出並將其指向(新創建的)FD 3。如果您直接執行它,這將不起作用,因為 FD 3 不會去任何地方,但我們可以將它合併到使用它的類似這樣的東西中:
( grep "..." >&3 ) 3>&1 1>/dev/null
括號中的命令輸出到 FD 3。之後的重定向 1) 將 FD 3(現在實際上有內容)指向 FD 1,以及 2) 然後再次將 FD 1 引導走(沒有效果)。最終結果是您將
grep "..."
再次獲得標準輸出的輸出,這正是它本來應該沒有大驚小怪的地方。這種重定向的實際用途類似於
cmd 3>&1 1>&2 2>&3 3>&- | foo
它交換 FD 1 和 2,使用 FD 3 作為臨時儲存點。它有時也用於 shell 腳本技巧,例如在 POSIX sh 中使用
( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )
. 否則,命令天生按數量使用任何非標准文件描述符是相當罕見的(當然,許多人自己打開一個文件並得到一個)。