抓取exec的输出

时间:2011-09-03 10:45:33

标签: c terminal exec fork

所以我试着写一些需要抓取命令输出的东西然后生病,然后将它传递给另一个程序。

但我有一个问题,我无法弄清楚如何获取命令输出并存储它 以下是我所拥有的样本

if(fork() == 0){
   execl("/bin/ls", "ls", "-1", (char *)0);
   /* hopefully do something with the output here*/
}else{
  *other stuff goes here*
 }`

所以基本上我想知道是否有任何方法可以从“execl”获取输出并将其传递给其他东西(例如通过将其存储在某种缓冲区中)。

任何建议都会很棒。谢谢你们..“

4 个答案:

答案 0 :(得分:33)

您必须使用pipe()从父进程到子进程创建管道。 然后,您必须使用standard ouputerror outputdup(STDOUT_FILENO)和dup2(STDERR_FILENO)重定向到管道,并在父进程中从管道中读取。 它应该工作。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define die(e) do { fprintf(stderr, "%s\n", e); exit(EXIT_FAILURE); } while (0);

int main() {
  int link[2];
  pid_t pid;
  char foo[4096];

  if (pipe(link)==-1)
    die("pipe");

  if ((pid = fork()) == -1)
    die("fork");

  if(pid == 0) {

    dup2 (link[1], STDOUT_FILENO);
    close(link[0]);
    close(link[1]);
    execl("/bin/ls", "ls", "-1", (char *)0);
    die("execl");

  } else {

    close(link[1]);
    int nbytes = read(link[0], foo, sizeof(foo));
    printf("Output: (%.*s)\n", nbytes, foo);
    wait(NULL);

  }
  return 0;
}

答案 1 :(得分:19)

打开一个管道,然后更改stdout以匹配该管道。

 #include <sys/types.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>

 int pipes[2];

 pipe(pipes); // Create the pipes

 dup2(pipe[1],1); // Set the pipe up to standard output

之后,任何进入stdout的东西(例如通过printf)都会出现在管道[0]上。

FILE *input = fdopen(pipe[0],"r");

现在您可以像普通文件描述符一样读取输出。有关详细信息,请查看this

答案 2 :(得分:2)

感谢Jonathan Leffler,我优化了上面的代码,因为它无法一次性读取所有响应。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>

#define die(e) do { fprintf(stderr, "%s\n", e); exit(EXIT_FAILURE); } while (0);

int main() {
  int link[2];
  pid_t pid;
  char foo[4096 + 1];
  memset(foo, 0, 4096);

  if (pipe(link)==-1)
    die("pipe");

   if ((pid = fork()) == -1)
    die("fork");

  if(pid == 0) {

    dup2 (link[1], STDOUT_FILENO);
    close(link[0]);
    close(link[1]);
    execl("/bin/ls", "ls", "-1", (char *)0);
    die("execl");
  } else {
    close(link[1]);
    int nbytes = 0;
    std::string totalStr;
    while(0 != (nbytes = read(link[0], foo, sizeof(foo)))) {
        totalStr = totalStr + foo;
        printf("Output: (%.*s)\n", nbytes, foo);
        memset(foo, 0, 4096);
    }
    wait(NULL);
  }
  return 0;
}

答案 3 :(得分:0)

如果你想输出一个字符串 (char *),这里有一个选项(至少对于 Linux):

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <unistd.h>

char* qx(char** cmd, int inc_stderr) {
  int stdout_fds[2];
  pipe(stdout_fds);

  int stderr_fds[2];
  if (!inc_stderr) {
    pipe(stderr_fds);
  }

  const pid_t pid = fork();
  if (!pid) {
    close(stdout_fds[0]);
    dup2(stdout_fds[1], 1);
    if (inc_stderr) {
      dup2(stdout_fds[1], 2);
    }

    close(stdout_fds[1]);

    if (!inc_stderr) {
      close(stderr_fds[0]);
      dup2(stderr_fds[1], 2);
      close(stderr_fds[1]);
    }

    execvp(*cmd, cmd);
    exit(0);
  }

  close(stdout_fds[1]);

  const int buf_size = 4096;
  char* out = malloc(buf_size);
  int out_size = buf_size;
  int i = 0;
  do {
    const ssize_t r = read(stdout_fds[0], &out[i], buf_size);
    if (r > 0) {
      i += r;
    }

    if (out_size - i <= 4096) {
      out_size *= 2;
      out = realloc(out, out_size);
    }
  } while (errno == EAGAIN || errno == EINTR);

  close(stdout_fds[0]);

  if (!inc_stderr) {
    close(stderr_fds[1]);
    do {
      const ssize_t r = read(stderr_fds[0], &out[i], buf_size);

      if (r > 0) {
        i += r;
      }

      if (out_size - i <= 4096) {
        out_size *= 2;
        out = realloc(out, out_size);
      }

    } while (errno == EAGAIN || errno == EINTR);

    close(stderr_fds[0]);
  }

  int r, status;
  do {
    r = waitpid(pid, &status, 0);
  } while (r == -1 && errno == EINTR);

  out[i] = 0;

  return out;
}

int main() {
  char* argv[3];
  argv[0] = "ls";
  argv[1] = "-la";
  argv[2] = NULL;
  char* out = qx(argv, 0);
  printf("%s", out);
  free(out);
}