是否可以在 C 中寫入其他文件描述符?
如果我希望將所有標準輸出重定向到一個文件,我會執行
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
都是內置的,所以沒有fork
orexec
。相反,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
/zsh
的print -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()