File-Descriptors

將標準輸出 fd 傳遞給“讀取”系統呼叫,但它仍然可以正常工作

  • December 19, 2018

我將1(stdout)/ 2(stderr) 傳遞給read系統呼叫,但它仍然可以正常工作。然後我將0(stdin) 傳遞給write系統呼叫並發現它也有效!

int main(int argc, char** argv){
   char buf[1024] = "abcdefghi\n";

   write(0, buf, 10);

   char readbuf[1024] = {0};
   // read(1, readbuf, 10); works too
   read(2, readbuf, 10);
   write(2, readbuf, 10);

   return 0;
}

輸出:

abcdefghi
hey stdin  <-- I input this
hey stdin

很迷茫,我以為應該是錯誤。

實驗:

然後我嘗試重定向 fd 2。

$ ./a.out 2>/dev/null

這次讀取和第二次寫入都不是“可見的”。輸出是

abcdefgi

那麼stderr可以用於讀取嗎?

然後我關閉標準輸出和標準錯誤並製作兩個標準輸入副本:

int main(int argc, char** argv){
   char buf[1024] = "abcdefghi\n";

   close(1);
   close(2);

   dup2(0, 1);
   dup2(0, 2);

   write(0, buf, 10);

   char redbuf[1024] = {0};
   read(2, redbuf, 10);
   write(2, redbuf, 10);

   return 0;
}

它再次起作用。

輸出:

abcdefghi
hey stdin  <-- I input this
hey stdin

那麼stdin可以用來寫嗎?

我在這裡需要一些解釋。

問題

我想知道:

為什麼 stdout/stderr 可以用於讀取?

為什麼stdin可以用於寫?

三個流(stdin,stdout,stderr)在內部是一個流嗎?

如果不是,為什麼我會得到這個結果?

僅將 fd 0/1/2 用於輸入/輸出/錯誤是慣例。如果您在沒有重定向的情況下呼叫程序,則所有三個都指向您的 tty,並且您的 tty 是打開的,具有讀寫訪問權限。這意味著您可以根據需要讀取或寫入它們。您可以將它們稱為相同的流,儘管表達式流通常用於更高級別的 I/O,例如FILE在 C 或streamC++ 中。

這就是為什麼兩個或不重定向的範例都只是回顯您輸入的文本的原因。

另一方面,如果您進行重定向,shell 將以只讀或只寫訪問權限打開文件。在您的範例./a.out 2>/dev/null中,寫入0仍然連接到終端,因為它沒有被重定向,因此顯示在螢幕上。讀取2連接到只寫/dev/null,因此應該失敗,但您不會注意到與您的程序的區別。寫入2成功,但寫入/dev/null. 無效讀取和有效寫入/dev/null在您的終端上不可見。

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