C重定向终端描述符



是否可以将终端中写入的所有内容重定向到进程?

例如,在我启动进程后,如果我在终端中写入"命令",它应该重定向到进程中的管道或类似的东西。

是的,在程序启动后重定向程序(及其所有子进程(的所有终端输出应该是可行的。Unix程序通常通过写入标准输出(stdout(来写入终端。对于所有进程,标准输出始终在文件描述符编号1(C常量为STDOUT_FILENO(上。您可以使用dup2()系统调用将任何文件描述符编号替换为另一个文件描述符。

因此,您可以使用int fds[2]; pipe(fds);创建一个管道。然后fds[1]将是一个文件描述符编号,您可以使用它来写入管道。如果执行dup2(fds[1], STDOUT_FILENO);,则标准输出也将写入管道。(之后您可以close(fds[1]);,因为您可能不需要它,现在您可以使用stdout了。(

您还可以打开一个文件,先用fd = open("filename", O_WRONLY);,然后用dup2(fd, STDOUT_FILENO);进行写入,这样写入stdout的所有内容都会进入您的文件。

请注意,在执行任何可能写入stdout的操作之前,您需要在程序一开始就重定向stdout。


以上技巧将使标准输出进入管道,而不是终端。如果您希望输出进入终端,在文件的管道中获得输出的副本,这更困难,但也可以做到。您需要创建一个内部管道,然后创建dup2(that_pipe, STDOUT_FILENO);,以便stdout写入该管道。然后,您需要从该管道读取(可能使用poll(),然后使用read()(,并将您获得的所有内容1(写入终端,2(写入程序外部的另一个管道或文件。因此,如果要复制输出,您需要两个管道

tee命令从shell执行此操作(将stdout复制到文件(。


这种dup2()方法并非无懈可击,因为Unix终端(即使使用GUI终端模拟器而不是硬件控制台(也是/dev中的一个设备。您可以在shell中键入tty,也可以在C中使用ttyname(STDOUT_FILENO)来查看/dev中的哪个文件对应于stdout正在写入的终端。原则上,任何程序(在同一用户帐户下(都可以使用该文件名打开终端设备并对其进行写入,而无需请求任何其他程序的许可。您可以使用write程序从shell轻松尝试:

echo hello world | write $(whoami) /dev/ttys123

其中/dev/ttys123是通过在其他终端窗口中键入tty得到的任何内容(在不同的操作系统上,例如Linux和MacOS,名称看起来有点不同(。您应该会看到hello world出现在另一个窗口中。

从一个子进程,没有。你必须在父进程中设置它,并让它向下传播到子进程(除非有某种疯狂的破解(。

从shell,您可以重定向。

exec >file

这将把标准输出重定向到file,并且它将应用于将来在shell中运行的所有命令。如果你愿意,你可以把它变成一个函数。

最新更新