C

是否可以在 C 中寫入其他文件描述符?

  • August 12, 2017

如果我希望將所有標準輸出重定向到一個文件,我會執行

my_prog 1> out

如果我希望對 stderr 做同樣的事情,我會執行

my_prog 2> err

但是,我知道在 shell 中還有其他文件描述符。例如,這個問題的最佳答案使用第三個文件描述符,可以通過命令行向其發送數據

echo "Some console message" 1>&3

有沒有辦法讓 C 程序寫入這個文件描述符?在沒有其他程序讀取它的情況下寫入它,是否也將其輸出發送到終端?

我對 C 不是很熟悉,所以可能有更好的方法,但你可以簡單地使用系統呼叫(man 2 write):

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

寫入數據的發送位置取決於文件​​描述符打開的內容。只有當文件描述符屬於終端時,數據才會到達終端。

如果您寫入管道或套接字而另一端不讀取數據,則寫入應用程序(即write()呼叫)將在緩衝區已滿時阻塞。

您可以在中查看文件描述符/proc/$PID/fd

澄清更多的事情。在:

echo foo >&3

echo沒有寫入"foo\n"它的文件描述符 3。echo總是寫入標準輸出,寫入它的文件描述符 1。它write()使用整數作為第一個參數呼叫系統呼叫1,指向記憶體中以foo\n作為第二個參數開頭的區域的指針和4( )的長度foo\n作為第三個。

在 C 中,您將編寫它write(1, "foo\n", 4)。在上面的程式碼中,shell在呼叫之前將 fd 1 重定向到與在 fd 3 上打開相同的打開文件描述echo(通過dup2()系統呼叫)。因此,即使它在功能上是等效的,但它與做write(3, "foo\n", 4). 實際上,它類似於(簡化):

if (pid = fork())
 waitpid(pid, ...);
else {
 dup2(3, 1);
 execlp("echo", "foo", 0);
} 

echo做了一個write(1, "foo\n", 4)

除了在幾乎所有的 shell 中,echo都是內置的,所以沒有forkor exec。相反,shell 會:

saved_stdout = dup(1);
dup2(3, 1);
builtin_echo("foo");
dup2(saved_stdout, 1); close(saved_stdout); /* restore stdout */

(哪裡builtin_echo()write(1, "foo\n", 4)在同一過程中執行的函式)。

對於執行此操作的命令write(3, "foo\n", 4),您可以查看ksh/zshprint -u3 foo內置命令。

現在,每個程序都可以隨意使用文件描述符。除了 0、1 和 2 按約定為標準輸入、標準輸出和標準錯誤保留。其他 fds 通常並不特殊,但在 shell(它只是一種類型的應用程序)中,fds 0 到<some-value>某個值至少為 9 的位置保留供(shell)使用者使用。外殼不會與它們混合在一起作為自己的內部湯。例如,我的saved_stdout = dup(1)上面是一個近似值。實際上,shell 將確保saved_stdout值大於<some-value>.

現在,由於 0、1、2 之外的 fd 沒有附加約定,因此您不能期望 fd 3 上會打開任何東西。很可能它將被關閉。或者如果不是,您的腳本的呼叫者很可能只是忘記關閉它(或向其添加O_CLOEXC標誌),因為沒有理由讓它為您打開,因為沒有人希望在 fd 3 上打開任何東西.

如果您知道 fd 3 已經對某些東西開放,通常由您事先在同一個腳本中打開,您將使用 fd 3,例如:

{
  var=$(cmd 2>&1 >&3)
} 3>&1

在我們將fd 3用於dup()fd 1之前, fd 3 已被定義為fd 1 的一個。cmd``dup()

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