【问题标题】:Redirecting stdout, don't understand behavior重定向标准输出,不理解行为
【发布时间】:2016-04-09 18:24:33
【问题描述】:

我一直在尝试使用 dup2 进行简单的 i/o 重定向。我完全按照其他人所说的代码进行了操作,但仍然没有成功。

int out = open("stdoutput", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
printf("STANDARD OUT\n");
dup2(out, 1);
printf("SEND TO FILE\n");
dup2(1, out);
close(out);
printf("BACK TO STANDARD OUT\n");

这会将 STANDARD OUT 打印到终端并 发送到文件 返回标准 到文件。为什么不切换回来?

我还想要一个 fork/exec 输出标准输出到一个文件。

int out2 = open("execout", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
printf("STANDARD OUT\n");
dup2(out2, 1);
if(fork() == 0)
{
    execvp("time", NULL);
    perror(NULL);
}

dup2(out2, 1);
close(out2);
printf("BACK TO STANDARD OUT\n");

这会打印到终端:

标准 TERM_PROGRAM=Apple_Terminal:没有这样的文件或目录 0.00 真实 0.00 用户 0.00 系统

到文件执行,它会打印: 回归标准

exec 调用 time 似乎还有一些额外的问题(没有找到它,但仍然打印它?)但我的主要问题是 I/O 重定向无法正常工作。

提前感谢您的帮助。


更新:似乎有一个问题,具体是 exec 没有将输出发送到文件。代码:

int output_file = open("gcc_output", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);

if(fork() == 0)
{
    dup2(output_file, 1);
    close(output_file);
    char *args[] = {"gcc", path, NULL};
    printf("THIS GOES TO FILE");
    execvp(args[0], args); // gcc output, errors etc. go to terminal
    perror("exec");
    exit(2);
}

exec 是否会导致它丢失文件描述符之类的?

【问题讨论】:

  • 它不会切换回来,因为out1 在第一个dup2 调用之后是相同的,所以第二个dup2 调用什么都不做。
  • 值得检查您的dup2 调用结果以确认这一点。
  • 在调用系统函数dup2()open()时,一定要检查返回值以保证操作成功。
  • exec 是否会导致它丢失文件描述符或其他内容? 不会,但您生成的命令可能会弄清楚如何将其输出发送到终端。在strace -f -o /path/to/output/file /path/to/your/executable ... 下运行您的可执行文件,以查看系统调用exec()'d 进程的内容。 (在 fork() 失败后调用 exit() 可能会导致各种问题 - 父母的退出处理程序的子副本被调用,父母的的子副本中的数据/i> IO 缓冲区被刷新到 parentfork() 时打开的文件。请改用_exit()。)

标签: c io dup2


【解决方案1】:

dup2(from, to)将文件描述符from复制到文件描述符to;如果to 是打开的,它会在被覆盖之前静默关闭。

在您的第一个示例中,您打开文件stdoutput 进行写入;它被赋予尽可能低的描述符编号(可能为 3);然后您的dup2(out2, 1) 将此描述符复制到标准输出描述符 1 上;原始标准输出被静默关闭。现在有 4 个打开的描述符:

  • 0 是原始标准输入
  • 1 被打开以写入文件stdoutput
  • 2 是原始标准输出
  • 3 被打开以写入文件stdoutput

最后,您尝试通过将文件描述符 1 复制到文件描述符 3 上来“恢复”原始标准输出。

相反,您应该将原始标准输出存储到dup的另一个文件描述符中:

int out = open("stdoutput", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
printf("STANDARD OUT\n");
int saved_stdout = dup(1); // create a copy of the stdout file descriptor
dup2(out, 1);
close(out);                // close the extra descriptor
printf("SEND TO FILE\n");
dup2(saved_stdout, 1);     // copy the saved stdout file descriptor to 1
close(saved_stdout);       // close the copy of stdout
printf("BACK TO STANDARD OUT\n");

您的execvp 电话也中断了;应该有额外的参数,即命令名称; time 也不会打印当前日期,而是一个需要另一个命令作为参数的命令 - 也许您想改为执行 date 命令?此外,您希望在 fork 之后的子进程中执行 dup2 only!请尝试以下操作:

int out2 = open("execout", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
printf("STANDARD OUT\n");
if (fork() == 0) {
    dup2(out2, 1);
    close(out2);
    execvp("date", "date", (char *)NULL);
    perror("exec");
    exit(2);
}
close(out2);
printf("STILL POINTING TO STANDARD OUT\n");

【讨论】:

  • 感谢您的明确解释。 exec 仍然有问题(更新了我的问题)。
猜你喜欢
  • 1970-01-01
  • 2014-06-14
  • 2014-01-20
  • 2011-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多