21

我正在处理一项任务,其中程序将文件描述符作为参数(通常来自 exec 调用中的父级)并从文件中读取并写入文件描述符,在我的测试中,我意识到该程序可以工作从命令行,如果我使用 0、1 或 2 作为文件描述符,则不会给出错误。这对我来说很有意义,只是我可以写信给标准输入并让它显示在屏幕上。

对此有解释吗?我一直认为标准输入/标准输出有一些保护,你当然不能从标准输出 fprintf 到标准输入或 fgets。

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
    char message[20];
    read(STDOUT_FILENO, message, 20);
    write(STDIN_FILENO, message, 20);

    return 0;
}
4

6 回答 6

19

尝试在标记为只读的文件上写入,反之亦然,将导致writeread返回 -1,并失败。在这种特定情况下,stdin 和 stdout 实际上是同一个文件。本质上,在你的程序执行之前(如果你不做任何重定向),shell 会:

  if(!fork()){
       <close all fd's>
       int fd = open("/dev/tty1", O_RDWR);
       dup(fd);
       dup(fd);
       execvp("name", argv);
  }

因此,stdin、out 和 err 都是同一个文件描述符的副本,为读写而打开。

于 2011-10-06T20:41:42.177 回答
3
read(STDIN_FILENO, message, 20); 
write(STDOUT_FILENO, message, 20);

应该管用。注意 - 标准输出与标准输入不同(即使在命令行上)。您可以将另一个进程的输出作为标准输入提供给您的进程,或者将标准输入/标准输出安排为文件。

fprintf/fgets 有一个缓冲区——从而减少了系统调用的次数。

于 2011-09-12T06:05:22.387 回答
1

文件描述符 0、1 和 2 很可能都对读写都是开放的(实际上它们都引用相同的底层“打开文件描述”),在这种情况下,您正在做的事情将起作用。但据我所知,没有保证,所以它也可能不起作用。我确实相信POSIX在某处指定如果在shell调用程序时将stderr连接到终端,它应该是可读可写的,但我无法立即找到参考。

一般来说,我建议不要从 stdout 或 stderr 读取,除非您正在寻找一个从中读取密码的终端,并且 stdin 已被重定向(不是 tty)。而且我建议永远不要写入标准输入 - 这很危险,您最终可能会破坏用户不希望写入的文件!

于 2011-09-12T13:10:34.447 回答
1

最佳猜测 - stdin 指向输入来自哪里,你的终端和 stdout 指向输出应该去哪里,你的终端。因为它们都指向同一个地方,所以它们可以互换(在这种情况下)?

于 2011-09-12T05:58:47.593 回答
1

如果您在 UNIX 上运行程序

myapp < input > output

您可以打开 /proc/{pid}/fd/1 并从中读取,打开 /proc/{pid}/fd/0 并写入它,例如,复制outputinput. (可能有更简单的方法可以做到这一点,但我知道它有效)

如果你下定决心,你可以做任何令人困惑的事情。;)

于 2011-09-12T07:35:03.360 回答
0

如果要将消息写入 stdin,可以打开当前 tty,并调用write系统调用将消息写入此 fd:

string console_cmd = "hello";
string tty = ttyname(STDIN_FILENO);
int fd = open(tty.c_str(), O_WRONLY);
write(fd, console_cmd.c_str(), console_cmd.size());

同样,从标准输出读取。

于 2016-08-16T13:56:42.630 回答