popen()替代方案

13

我的问题是对这个问题的扩展:popen creates an extra sh process

动机:

1)我的程序需要创建一个子进程,该子进程对文件执行tail操作。我需要逐行处理输出内容。这就是我使用popen的原因,因为它返回FILE *。我可以轻松获取单行内容,进行处理并打印出来。

popen的一个问题是你无法获得子进程(tail命令)的pid。

2)在子进程完成之前,我的程序不应该退出。因此,我需要执行wait;但是没有pid,我无法执行。

如何同时实现两个目标?

一种可能的(折中的)解决方案:执行execvp("tail -f file > tmpfile"),然后继续读取tmpfile。但我不确定这个解决方案有多好。

4个回答

20

为什么你不使用管道/分叉/执行方法?

pid_t pid = 0;
int pipefd[2];
FILE* output;
char line[256];
int status;

pipe(pipefd); //create a pipe
pid = fork(); //span a child process
if (pid == 0)
{
// Child. Let's redirect its standard output to our pipe and replace process with tail
 close(pipefd[0]);
 dup2(pipefd[1], STDOUT_FILENO);
 dup2(pipefd[1], STDERR_FILENO);
 execl("/usr/bin/tail", "/usr/bin/tail", "-f", "path/to/your/file", (char*) NULL);
}

//Only parent gets here. Listen to what the tail says
close(pipefd[1]);
output = fdopen(pipefd[0], "r");

while(fgets(line, sizeof(line), output)) //listen to what tail writes to its standard output
{
//if you need to kill the tail application, just kill it:
  if(something_goes_wrong)
    kill(pid, SIGKILL);
}

//or wait for the child process to terminate
waitpid(pid, &status, 0);

1
在读取结束后,我需要在close(pipefd[0])之前关闭管道吗?还是在kill之前? - hari
顺便提一下,如果您使用GLib,那么有一个预先制作的实现具有大量功能,而且它处理所有错误代码等。请参见http://developer.gnome.org/glib/2.30/glib-Spawning-Processes.html(免责声明:我虽然是多年前实现的) - Havoc P
@havoc或libHX的HXproc_*函数族,不像glib那样使用参数过多的函数。 - jørgensen
当然,只是提到我知道的库。 - Havoc P

1
  1. 您可以使用pipeexec*系列函数和fdopen。这是非标准的,但popen也是如此。
  2. 您不需要wait。只需读取管道直到EOF
  3. execvp("tail -f file > tmpfile")不起作用,重定向是shell的一个特性,您在此处没有运行shell。即使它起作用,这也是一个可怕的解决方案。假设您已经读到了文件的末尾,但子进程还没有结束。你该怎么办?

4
它们不是非标准的,只是超出了 C 标准。它们是 POSIX 标准的一部分。 - kennytm

0

你可以使用wait,因为它不需要等待一个特定的PID,而是等待任何子进程退出。如果你创建了其他子进程,你可以跟踪它们,如果wait返回一个未知的PID,你可以假设它来自于你的popen进程。


如果在某些错误情况下,我需要杀死子进程,我可以这样做吗?(首先会出现这种情况吗?)我只是在胡思乱想。 - hari
假设程序出现错误并需要退出,wait会确保在退出主程序之前也杀死/终止子进程吗? - hari
你可以创建一个进程组,然后简单地调用kill(getpgrp(), SIGTERM);将会杀死所有进程。 - DarkDust

0

我不确定你为什么需要子进程的进程ID。当子进程退出时,管道读取将返回EOF。如果您需要终止子进程,只需关闭管道即可。


一个子进程可以是“tail -f”,它永远不会返回。在这种情况下,当我按下ctrl-C时,在我的主程序退出之前,我希望子进程“tail -f”能够完成。 - hari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接