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

Ale*_*lex 2 c file-descriptors

如果我希望将所有标准输出重定向到一个文件,我会运行

my_prog 1> out
Run Code Online (Sandbox Code Playgroud)

如果我想对 stderr 做同样的事情,我会运行

my_prog 2> err
Run Code Online (Sandbox Code Playgroud)

但是,我知道在 shell 中还有其他文件描述符。例如,这个问题的最高答案使用第三个文件描述符,可以通过以下方式从命令行发送数据

echo "Some console message" 1>&3
Run Code Online (Sandbox Code Playgroud)

C 程序有没有办法写入这个文件描述符?在没有其他程序读取它时写入它,是否也将其输出发送到终端?

Sté*_*las 6

再澄清几件事。在:

echo foo >&3
Run Code Online (Sandbox Code Playgroud)

echo不写入"foo\n"其文件描述符 3.echo始终写入 stdout,写入其文件描述符 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);
} 
Run Code Online (Sandbox Code Playgroud)

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

除了在几乎所有 shell 中,echo都是内置的,所以没有forkor exec。相反,外壳会:

saved_stdout = dup(1);
dup2(3, 1);
builtin_echo("foo");
dup2(saved_stdout, 1); close(saved_stdout); /* restore stdout */
Run Code Online (Sandbox Code Playgroud)

(其中builtin_echo()write(1, "foo\n", 4)在同一进程中执行的函数)。

对于执行 的命令write(3, "foo\n", 4),您可以查看ksh/zshprint -u3 foo内置命令。

现在,每个进程都可以随意使用文件描述符。除了 0、1 和 2 按照惯例保留给 stdin、stdout 和 stderr。其他 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,通常由您事先在同一个脚本中打开,例如:

 {
   var=$(cmd 2>&1 >&3)
 } 3>&1
Run Code Online (Sandbox Code Playgroud)

在我们将 fd 3 定义为dup()fd 1 的 a之前,将其用于cmddup()其返回到 fd 1 上。