一個命令怎麼可能有多個輸出?
在這個答案的最底部,吉爾斯提到一個命令可以有多個輸出或輸入。
是的,有
cat foo bar | something
, 用於同時具有foo
和bar
作為輸入,還有tee
用於輸出;但這似乎並不是他所說的。一個程序怎麼可能有多個輸入或輸出?
這個
cat foo bar
例子不是我的意思。這裡cat
一次只有一個輸入和一個輸出。
tee
是一個例子:它輸出到所有參數,同時加上它的標準輸出。使用與我之前的答案相同的 ASCII 藝術圖,這是tee foo bar
它在終端中執行時的樣子。+------------------+ | tee | ===|<stdin | +------------+ → | | | terminal | | stdout>|=========|<input | | | → ##==|< | | | || +------------+ | stderr>|=====## | | → | | +-------------+ | 3>|=======|> file "foo" | | | → +-------------+ | | +-------------+ | 4>|=======|> file "bar" | | | → +-------------+ | | +------------------+
在這個例子中,
tee
發送“有用的”輸出到三個通道:到終端(因為這是它的標準輸出連接到的地方),以及到兩個文件。此外,tee
還有一個錯誤輸出通道。一個程序通常具有三個輸入/輸出通道,由它們的文件描述符編號標識:
- 標準輸入(簡稱stdin,文件描述符編號為0);
- 標準輸出(簡稱stdout,文件描述符編號1);
- 標準錯誤(簡稱stderr,文件描述符編號2)。
文件描述符 0、1 和 2 的用途只是一個約定問題——沒有任何東西強製程序不能嘗試寫入文件描述符 0 或從描述符 1 和 2 讀取——但這是一個幾乎普遍遵循的約定。
如果您從終端執行程序,文件描述符 0、1 和 2 開始連接到該終端,除非它們已被重定向。其他文件描述符開始關閉,如果程序打開其他文件將使用。
特別是,所有命令都有兩個輸出:標準輸出(對於命令的有效負載,“有用的”輸出)和標準錯誤(對於錯誤或資訊性消息)。
shell (
command1 | command2 | command3 | …
) 中的管道將每個命令的標準輸出連接到下一個命令的標準輸入。所有命令的標準錯誤都會發送到終端(除非重定向)。Shell 提供了重定向其他文件描述符的方法。您可能已經遇到
2>&1
或2>file
重定向標準錯誤。請參閱 何時使用額外的文件描述符?以及它連結到的其他文章,以獲取其他文件描述符的操作範例。功能豐富的 shell 還提供程序替換以將文件重定向推廣到管道命令,這樣您就不會局限於每個命令都有一個輸入和一個輸出的線性管道。
很少有命令會嘗試訪問大於 2 的文件描述符,除非它們打開了文件(打開文件會選擇一個空閒的文件描述符並將其編號返回給應用程序)。一個例子是 GnuPG,它希望讀取數據以對其標準輸入進行加密/解密/簽名/驗證,並將結果寫入標準輸出。
--passphrase-fd
可以告訴它使用該選項讀取不同文件描述符上的密碼。GnuPG 還具有報告其他文件描述符狀態數據的選項,因此您可以在 stdout 上輸出有效負載,在 stderr 上輸出錯誤消息,並在另一個文件描述符上顯示狀態資訊。這是一個將管道命令的輸出用作密碼的範例:echo fjbeqsvfu | rot13 | gpg -d --passphrase-fd=3 3<&0 <file.encrypted >file.plaintext