执行控制台程序,写入标准输入并使用管道读取结果

时间:2014-12-28 09:46:50

标签: c++ linux gcc pipe

我需要执行我的控制台程序,将一些值写入标准输入并使用管道读取结果。我试图实现它。这段代码完美无缺。但我认为还有其他更简单的方法来实现它。你有什么想法吗?

pid_t pid = fork();
std::string output_data;
if(pid < 0)
{
    printf("Error\n");
}
else if(!pid)
{
    FILE* process = popen(program.c_str(), "r");
    char temp_data[128];
    if(process)
    {
        while(fgets(temp_data, sizeof(temp_data), process))
        {
            output_data.append(temp_data);
        }
    }
    pclose(process);
    exit(1);
}
else
{
    FILE* process = popen(program.c_str(), "w");
    std::string output_data;
    char temp_data[128];
    if(process)
    {
        fwrite("5", 1, sizeof(int), process);
    }
    pclose(process);
}

1 个答案:

答案 0 :(得分:0)

看起来您的代码将运行4个进程:一个进程分成2个,然后使用popen()分别执行每个进程。 popen()不仅会创建一个管道,还会创建一个通过该管道连接的子进程,因此调用popen()的每个进程都会创建一个子进程。

你应该决定如何去:让popen()完成所有的工作,但是不要使用fork(),或者让pipe()自己创建管道并使用fork() - 那是我下面的代码。

还有一个很大的区别:popen()不仅会分叉,而且还会在子代中执行另一个程序。我的例子保留在同一个可执行文件中如果你想在子节点中执行另一个程序,那么popen()可能非常有用,但是你不应该使用fork()。

int fsd[2]; // write to fds[1], read from fds[0]
pipe(fds);  // creates the pipe with read+write file descriptors in fds
id_t pid = fork();
std::string output_data;
if(pid < 0)
{
    printf("Error\n");
}
else if(!pid)
{
    close(fds[1]); // else we'll never detect end of input
    FILE* process = fdopen(fds[0], "r");
    char temp_data[128];
    if(process)
    {
        while(fgets(temp_data, sizeof(temp_data), process))
        {
            output_data.append(temp_data);
        }
    }
    pclose(process);
    exit(1);
}
else
{
    close(fds[0]); // just to clean up
    FILE* process = fdopen(fds[1], "w");
    std::string output_data;
    char temp_data[128];
    if(process)
    {
        fprintf(process, "5\n"); // your fwrite("5",...) worked by luck only
    }
    pclose(process);
}

最后,如果您希望您的流程启动另一个可执行文件,请写入该可删除文件然后从中读取,您需要执行此操作:

创建2个管道,一个用于从父级写入子级,另一个用于从子级写回到父级,然后执行一些魔术来重新分配文件描述符:

int p2c[2]; pipe(p2c); // parent to child
int c2p[2]; pipe(c2p); // child to parent
if(fork()) { // parent -  I ignore error checks here
    close(p2c[0]); // the child reads from that
    close(c2p[1]); // the child writes to that
    FILE * f_w = fdopen(p2c[1],"w");
    ... write some data to the child using f_w ...
    fclose(f_w);
    FILE * f_r = fdopen(c2p[0],"r");
    ... read some data from the child using f_r ...
    fclose(f_r);
    wait(0); // just to avoid a zombie
} else { // in the child, change stdin and stdout
    close(p2c[1]); close(0); dup(p2c[0]); close(p2c[0]);
    close(c2p[0]); close(1); dup(c2p[1]); close(c2p[1]);
    ... now use execv or something similar to run the other executable
}