【问题标题】:using dup2 and pipe to redirect stdin使用 dup2 和管道重定向标准输入
【发布时间】:2017-11-03 17:52:14
【问题描述】:

我有一个程序 A,它从标准输入获取两个参数,并根据参数以唯一的代码退出。我正在编写一个程序 B,它使用 fork 和 exec 调用程序 A,并让程序 B 打印出程序 A 退出的代码。出于某种原因,程序 A 似乎没有在 fork 的子进程中获取我通过管道传递给它的数据。我不确定我是否将正确的数据传递给子进程。

有人可以帮帮我吗?谢谢!

这是我的代码:

int program_B(void) {
char var_a[256];
char var_b[256];
int fd[2];

 // Read from stdin 
char *sendarray[2];
sendarray[0] = var_a;
sendarray[1] = var_b;


if(fgets(var_a, MAXLINE, stdin) == NULL) {
    perror("fgets");
    exit(1);
}

if(fgets(var_b, MAXLINE, stdin) == NULL) {
    perror("fgets");
    exit(1);
}

if (pipe(fd) == -1) {
  perror("pipe");
  exit(1);
}

int pid = fork();

// Child process -- error seems to be here. 
if (pid == 0) {

    close(fd[1]);

    dup2(fd[0], fileno(stdin));

    close(fd[0]);

    execl("program_A", NULL);

    perror("exec"); 
    exit(1);

} else {

    close(fd[0]);
    write(fd[1], sendarray, 2*sizeof(char*));
    close (fd[1]);

    int status; 

      if (wait(&status) != -1) {

        if (WIFEXITED(status)) {


            printf("%d\n", WEXITSTATUS(status));


        } else {
          perror("wait");
          exit(1);
        }
      }


}







return 0;
}

【问题讨论】:

  • 请注意,不告诉程序它叫什么是一种惯例。您的execl() 行应该是execl("program_A", "program_A", (char *)NULL);。第一个参数是要执行的文件的路径名(当前目录下的programA),第二个是被执行程序的argv[0]中的值。请注意,没有什么可以阻止您使用 execl("progam_A", "hypothetical-misnomer", (char *)NULL); 给它一个与路径名无关的 argv[0] 值。

标签: c pipe exec dup2


【解决方案1】:

您将错误的数据传递给子进程。

我假设var_avar_b 是您要发送到程序A 的字符串。它们都是字符数组 类型,在C 中是相同的东西 作为 指向 char 的指针(实际上指针和数组之间存在细微差别,但这与此问题无关)。所以它们实际上只是指向每个参数的第一个字节的指针。 sendarray,然而是一个 char-pointers 数组,它与 char-pointer 的指针相同。请记住这一点。

当调用write() 时,第二个参数告诉它数据在内存中的位置。通过传递sendarray,write 认为sendarray 指向您要写入的数据,尽管它实际上指向另一个指针。因此,var_avar_b 的指针值(sendarray 指向的)被写入管道。

因此您必须将var_avar_b 传递给write(),因为它们是指向您要发送的实际数据的指针。您还必须知道该数据有多长(多少字节)。如果var_avar_b 指向以null 结尾的字符串,您可以使用strlen() 来确定它们的长度。

最后一件事:我不知道您的程序 A 究竟是如何从像 stdin 这样的连续字节流中获取 2 个参数的,但假设它逐行读取,您显然必须从程序 B 也是如此。

因此,将所有这些放在一起,您的 write 语句应该如下所示:

write(fd[1], var_a, strlen(var_a));
write(fd[1], "\n", 1);
write(fd[1], var_b, strlen(var_b));

当然,如果我所做的任何假设是错误的,您必须适当地采用此代码。

【讨论】:

  • 不需要换行符 - 可能 - 因为 fgets() 调用保留了输入数据中的换行符(可能)。有关于超长行等的警告,输入行中间的空字节,以及其他各种可能的故障,这些故障大多可以忽略。
  • fgets() 从输入中读取一行,但也将换行符存储在结果中。
  • 顺便说一句。所有 C 函数都有手册页,其中解释了此类细节。在您的终端或 goolge 中输入 man 3 fgets 以查看它们。 ;-)
  • 你的代码向程序发送了三行;我的印象是它只需要两行。因此不需要中间的write()。这不是很清楚(“从标准输入获取两个参数的程序 A”没有使用正常的术语;它们是输入行而不是命令行参数),但是……
  • goolge --> 谷歌,如果你很快的话。您最多可以编辑 cmets 5 分钟。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-26
  • 1970-01-01
  • 2013-07-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多