从系统捕获标准输出()命令优化

我试图通过system()来启动外部应用程序 – 例如system("ls") 。 我想捕获它的输出,所以我可以把它发送到另一个函数进行进一步处理。 C / C ++中最好的方法是什么?

从popen手册:

 #include <stdio.h> FILE *popen(const char *command, const char *type); int pclose(FILE *stream); 

尝试popen()函数。 它执行一个像system()这样的命令,但将输出导入到一个新的文件中。 返回指向stream的指针。

  FILE *lsofFile_p = popen("lsof", "r"); if (!lsofFile_p) { return -1; } char buffer[1024]; char *line_p = fgets(buffer, sizeof(buffer), lsofFile_p); pclose(lsofFile_p); 

编辑:误读的问题,因为想传递到另一个程序的输出,而不是另一个function。 popen()几乎肯定是你想要的。

系统可以让您完全访问shell。 如果你想继续使用它,你可以通过系统(“ls> tempfile.txt”)把它的输出redirect到一个临时文件,但是select一个安全的临时文件是一件痛苦的事情。 或者,你甚至可以通过另一个程序redirect它:system(“ls | otherprogram”);

有些人可能会推荐popen()命令。 如果你可以自己处理输出,这就是你想要的:

 FILE *output = popen("ls", "r"); 

这会给你一个FILE指针,你可以通过命令的输出来读取它。

您也可以使用pipe()调用来创build与fork()组合的连接以创build新的进程,dup2()更改它们的标准input和输出,exec()运行新的程序,wait()在主程序中等待他们。 这只是像pipe壳一样设置pipe道。 有关详细信息和示例,请参阅pipe()手册页。

函数popen()等不会redirectstderr等; 我为此写了popen3()

最有效的方法是直接使用stdout文件描述符,绕过FILEstream:

 pid_t popen2(const char *command, int * infp, int * outfp) { int p_stdin[2], p_stdout[2]; pid_t pid; if (pipe(p_stdin) == -1) return -1; if (pipe(p_stdout) == -1) { close(p_stdin[0]); close(p_stdin[1]); return -1; } pid = fork(); if (pid < 0) { close(p_stdin[0]); close(p_stdin[1]); close(p_stdout[0]); close(p_stdout[1]); return pid; } else if (pid == 0) { close(p_stdin[1]); dup2(p_stdin[0], 0); close(p_stdout[0]); dup2(p_stdout[1], 1); dup2(::open("/dev/null", O_RDONLY), 2); /// Close all other descriptors for the safety sake. for (int i = 3; i < 4096; ++i) { ::close(i); } setsid(); execl("/bin/sh", "sh", "-c", command, NULL); _exit(1); } close(p_stdin[0]); close(p_stdout[1]); if (infp == NULL) { close(p_stdin[1]); } else { *infp = p_stdin[1]; } if (outfp == NULL) { close(p_stdout[0]); } else { *outfp = p_stdout[0]; } return pid; } 

要读取孩子使用popen2()输出,像这样:

 int child_stdout = -1; pid_t child_pid = popen2("ls", 0, &child_stdout); if (!child_pid) { handle_error(); } char buff[128]; ssize_t bytes_read = read(child_stdout, buff, sizeof(buff)); 

要写和读:

 int child_stdin = -1; int child_stdout = -1; pid_t child_pid = popen2("grep 123", &child_stdin, &child_stdout); if (!child_pid) { handle_error(); } const char text = "1\n2\n123\n3"; ssize_t bytes_written = write(child_stdin, text, sizeof(text) - 1); char buff[128]; ssize_t bytes_read = read(child_stdout, buff, sizeof(buff)); 

函数popen()pclose()可以是你正在寻找的东西。

看看glibc手册的例子。

在Windows中,不是使用system(),而是使用CreateProcess,将输出redirect到pipe道并连接到pipe道。

我猜这也是可能的一些POSIX的方式?

其实我只是查了一下,而且:

  1. popen是有问题的,因为这个过程是分叉的。 所以如果你需要等待shell命令的执行,那么你就有可能丢失它。 就我而言,我的程序在pipe道开始工作之前就已经closures了。

  2. 我结束了在Linux上使用tar命令的系统调用。 系统的返回值是焦油的结果。

所以: 如果你需要返回值 ,那么不是没有必要使用popen,它可能不会做你想要的。

在这个页面中: capture_the_output_of_a_child_process_in_c描述了使用popen与使用fork / exec / dup2 / STDOUT_FILENO方法的限制。

我在使用popen捕获tshark输出时遇到了问题。

我猜这个限制可能是我的问题:

它返回一个stdiostream,而不是原始文件描述符,这不适合asynchronous处理输出。

如果我有另一种方法的解决scheme,我会回到这个答案。

我不完全确定它可能在标准C中,因为两个不同的进程通常不共享内存空间。 我能想到的最简单的方法是让第二个程序将其输出redirect到一个文本文件(程序名> textfile.txt),然后读取该文本文件以进行处理。 但是,这可能不是最好的方法。