从exec获取输出

从exec获取输出,c,terminal,exec,fork,C,Terminal,Exec,Fork,我正试图编写一个C程序来获取命令输出,然后将其传递给另一个程序 我遇到了一个问题,我无法解决如何获取命令输出并存储它。下面是我所拥有的一个样本 if(fork() == 0){ execl("/bin/ls", "ls", "-1", (char *)0); /* do something with the output here */ } else{ //*other stuff goes here* } 因此,

我正试图编写一个C程序来获取命令输出,然后将其传递给另一个程序

我遇到了一个问题,我无法解决如何获取命令输出并存储它。下面是我所拥有的一个样本

if(fork() == 0){
   execl("/bin/ls", "ls", "-1", (char *)0);
   /* do something with the output here */
}
else{
    //*other stuff goes here*
}
因此,基本上我想知道是否有任何方法可以从“execl”获取输出并将其传递给其他东西(例如,通过将其存储在某种缓冲区中)


建议非常好。

您必须使用
pipe()
创建一个从父进程到子进程的管道。 然后必须使用
dup
dup2
标准输出
(STDOUT\u FILENO)和
错误输出
(STDERR\u 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;
}
#包括
#包括
#包括
#定义die(e)do{fprintf(stderr,“%s\n”,e);exit(exit_FAILURE);}while(0);
int main(){
int-link[2];
pid_t pid;
查富[4096];
如果(管道(连接)=-1)
模具(“管道”);
如果((pid=fork())=-1)
模具(“叉子”);
如果(pid==0){
dup2(链接[1],标准文件号);
关闭(链接[0]);
关闭(链接[1]);
execl(“/bin/ls”、“ls”、“-1”、(char*)0);
死亡(“执行”);
}否则{
关闭(链接[1]);
int nbytes=read(link[0],foo,sizeof(foo));
printf(“输出:(.*s)\n”,n字节,foo);
等待(空);
}
返回0;
}

打开一个管道,并更改标准输出以匹配该管道

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

 int pipes[2];

 pipe(pipes); // Create the pipes

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

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

谢谢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;
}
#包括
#包括
#包括
#包括
#包括
#定义die(e)do{fprintf(stderr,“%s\n”,e);exit(exit_FAILURE);}while(0);
int main(){
int-link[2];
pid_t pid;
查富[4096+1];
memset(foo,04096);
如果(管道(连接)=-1)
模具(“管道”);
如果((pid=fork())=-1)
模具(“叉子”);
如果(pid==0){
dup2(链接[1],标准文件号);
关闭(链接[0]);
关闭(链接[1]);
execl(“/bin/ls”、“ls”、“-1”、(char*)0);
死亡(“执行”);
}否则{
关闭(链接[1]);
int n字节=0;
std::字符串totalStr;
而(0!=(n字节=读取(链接[0],foo,sizeof(foo))){
totalStr=totalStr+foo;
printf(“输出:(.*s)\n”,n字节,foo);
memset(foo,04096);
}
等待(空);
}
返回0;
}

如果希望输出为字符串(char*),这里有一个选项(至少适用于Linux):

#包括
#包括
#包括
#包括
#包括
#包括
字符*qx(字符**cmd,内部有限公司){
国际标准普尔fds[2];
管道(标准管道);
国际标准与准则[2];
如果(!inc_stderr){
管道(标准管道);
}
常数pid_t pid=fork();
如果(!pid){
关闭(stdout_fds[0]);
dup2(stdout_fds[1],1);
如果(包括标准){
dup2(stdout_fds[1],2);
}
关闭(stdout_fds[1]);
如果(!inc_stderr){
关闭(stderru fds[0]);
dup2(stderr_fds[1],2);
关闭(stderr_fds[1]);
}
execvp(*cmd,cmd);
出口(0);
}
关闭(stdout_fds[1]);
const int buf_size=4096;
char*out=malloc(基本尺寸);
int out_size=buf_size;
int i=0;
做{
const ssize_t r=读取(标准输出fds[0],&out[i],单位大小);
如果(r>0){
i+=r;
}
如果(超出尺寸-i 0){
i+=r;
}

if(out_size-我感谢heaps!展示如何从中读取的伟大示例为您赢得了它。我可以阅读dup2、execl等上的手册页,其中解释了函数调用,但我不了解整体情况。有人能详细说明为什么我们需要fork吗?为什么我们在这样做时关闭链接,以及为什么等待(NULL)最后?实际上可能不需要fork。但如果您想在chile任务结束时执行操作,则必须fork一个新进程。等待确保父进程不会退出bedore child。我在我的副本第1.6节中找到了这一解释:“在子进程中,我们调用
exec
来执行命令[…]。这将用新的程序文件替换子进程。
fork
后跟
exec
的组合称为在某些操作系统上生成新进程。在UNIX系统中,这两个部分分为单独的函数。“好的,现在一切都开始有意义了。从手册页上看:
exec()
函数系列将当前进程映像替换为新的进程映像。“非常感谢伟大的awnser,很抱歉您没有获得胜利。在我看来,这是一个更清晰的答案,应该是最好的答案。”
#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;
}
#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);
}