【问题标题】:Execute program from within a C program从 C 程序中执行程序
【发布时间】:2010-09-09 09:48:22
【问题描述】:

我应该如何从我的C 程序中运行另一个程序?我需要能够将数据写入已启动程序的STDIN(可能从它的STDOUT中读取)

我不确定这是否是标准 C 函数。我需要能在 Linux 下工作的解决方案。

【问题讨论】:

    标签: c linux


    【解决方案1】:

    您想使用popen。它为您提供了一个单向管道,您可以通过它访问程序的标准输入和标准输出。

    popen 是现代 unix 和类 unix 操作系统的标准配置,Linux 就是其中之一 :-)

    类型

    man popen
    

    在终端中阅读更多信息。

    编辑

    popen 是否产生单向或双向管道取决于实现。在LinuxOpenBSD 中,popen 生成单向管道,它们是只读或只写的。在OS XFreeBSDNetBSD popen 上生成双向管道。

    【讨论】:

    • 请注意,它是标准输入标准输出,不能同时使用。
    • 在现代实现中,它是标准输入和标准输出。管道可以是双向的,但传统上它是单向的。
    • "man popen" 在 Ubuntu 9.04 上说“由于管道根据定义是单向的,类型参数可能只指定读取或写入,而不是两者”。
    • @freespace 有哪些实现?你能引用他们的文件吗?
    • @n.m.在 OS X 上 popen 允许单向管道:developer.apple.com/legacy/library/documentation/Darwin/…。 *BSD 似乎也是如此。
    【解决方案2】:

    不久前,我为其他人编写了一些示例 C 代码,展示了如何执行此操作。这是给你的:

    #include <sys/types.h>
    #include <unistd.h>
    #include <stdio.h>
    
    void error(char *s);
    char *data = "Some input data\n";
    
    main()
    {
      int in[2], out[2], n, pid;
      char buf[255];
    
      /* In a pipe, xx[0] is for reading, xx[1] is for writing */
      if (pipe(in) < 0) error("pipe in");
      if (pipe(out) < 0) error("pipe out");
    
      if ((pid=fork()) == 0) {
        /* This is the child process */
    
        /* Close stdin, stdout, stderr */
        close(0);
        close(1);
        close(2);
        /* make our pipes, our new stdin,stdout and stderr */
        dup2(in[0],0);
        dup2(out[1],1);
        dup2(out[1],2);
    
        /* Close the other ends of the pipes that the parent will use, because if
         * we leave these open in the child, the child/parent will not get an EOF
         * when the parent/child closes their end of the pipe.
         */
        close(in[1]);
        close(out[0]);
    
        /* Over-write the child process with the hexdump binary */
        execl("/usr/bin/hexdump", "hexdump", "-C", (char *)NULL);
        error("Could not exec hexdump");
      }
    
      printf("Spawned 'hexdump -C' as a child process at pid %d\n", pid);
    
      /* This is the parent process */
      /* Close the pipe ends that the child uses to read from / write to so
       * the when we close the others, an EOF will be transmitted properly.
       */
      close(in[0]);
      close(out[1]);
    
      printf("<- %s", data);
      /* Write some data to the childs input */
      write(in[1], data, strlen(data));
    
      /* Because of the small amount of data, the child may block unless we
       * close it's input stream. This sends an EOF to the child on it's
       * stdin.
       */
      close(in[1]);
    
      /* Read back any output */
      n = read(out[0], buf, 250);
      buf[n] = 0;
      printf("-> %s",buf);
      exit(0);
    }
    
    void error(char *s)
    {
      perror(s);
      exit(1);
    }
    

    【讨论】:

      【解决方案3】:
      1. 使用pipe(...) 创建两个管道,一个用于stdin,一个用于stdout
      2. fork(...) 进程。
      3. 在子进程中(fork(...) 返回 0 的那个)dup (...)stdin/stdout 的管道。
      4. exec[v][e]子进程中要启动的programm文件。
      5. 在父进程(fork)返回子进程的 PID)执行一个循环,从子进程的stdoutselect(...)poll(...)read(...))读取到缓冲区,直到 孩子终止(waitpid(...))。
      6. 如果孩子需要的话,最终在stdin 上提供输入。
      7. 完成后close(...) 管道。

      【讨论】:

        【解决方案4】:

        对于简单的单向通信,popen() 是一个不错的解决方案。但是,它对双向通信没有用处。

        IMO,imjorge (Jorge Ferreira) 给出了双向通信的大部分答案(80%?) - 但省略了一些关键细节。

        1. 父进程关闭用于向子进程发送消息的管道的读取端至关重要。
        2. 子进程关闭用于向子进程发送消息的管道的写入端至关重要。
        3. 父进程关闭用于向父进程发送消息的管道的写入端至关重要。
        4. 子进程关闭用于向父进程发送消息的管道的读取端至关重要。

        如果您不关闭未使用的管道末端,那么当其中一个程序终止时,您不会获得明智的行为;例如,孩子可能正在从其标准输入读取,但除非管道的写入端在孩子中关闭,否则它将永远不会获得 EOF(读取的零字节),因为它仍然打开管道并且系统认为它有时可能会开始写入该管道,即使它当前挂起等待从中读取内容。

        写入进程应考虑是否处理在没有读取进程的管道上写入时发出的 SIGPIPE 信号。

        您必须了解管道容量(取决于平台,可能只有 4KB)并设计程序以避免死锁。

        【讨论】:

          【解决方案5】:

          可以使用系统调用,阅读manpage for system(3)

          【讨论】:

            【解决方案6】:

            我认为你可以使用

            freopen

            为此。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-10-23
              • 1970-01-01
              • 2011-06-24
              • 2010-12-02
              • 1970-01-01
              相关资源
              最近更新 更多