直接在缓冲区中捕获命令行输出

时间:2010-01-19 06:58:44

标签: c

我想使用system()命令或execl执行命令,并希望直接在C中的缓冲区中捕获输出。是否有可能使用dup()系统调用或使用管道捕获缓冲区中的输出( )。我不想在使用mkstemp或任何其他临时文件之间使用任何文件。请帮帮我。谢谢。

我尝试用fork()创建两个进程并管道输出它正在工作。但是我不想使用fork系统调用,因为我要使用单独的线程无限地运行模块并且它调用了大量的fork ()和系统有时耗尽资源。

要清楚我正在做的是在缓冲区中捕获shell脚本的输出,处理输出并将其显示在我使用ncurses.Thankyou设计的窗口中。

5 个答案:

答案 0 :(得分:1)

这是一些用于捕获程序输出的代码;它使用exec()而不是system(),但通过直接调用shell可以直接容纳:

How can I implement 'tee' programmatically in C?

void tee(const char* fname) {
    int pipe_fd[2];
    check(pipe(pipe_fd));
    const pid_t pid = fork();
    check(pid);
    if(!pid) { // our log child
        close(pipe_fd[1]); // Close unused write end
        FILE* logFile = fname? fopen(fname,"a"): NULL;
        if(fname && !logFile)
                fprintf(stderr,"cannot open log file \"%s\": %d (%s)\n",fname,errno,strerror(errno));
        char ch;
        while(read(pipe_fd[0],&ch,1) > 0) {
                //### any timestamp logic or whatever here
                putchar(ch);
                if(logFile)
                        fputc(ch,logFile);
                if('\n'==ch) {
                        fflush(stdout);
                        if(logFile)
                                fflush(logFile);
                }
        }
        putchar('\n');
        close(pipe_fd[0]);
        if(logFile)
                fclose(logFile);
        exit(EXIT_SUCCESS);
    } else {
        close(pipe_fd[0]); // Close unused read end
        // redirect stdout and stderr
        dup2(pipe_fd[1],STDOUT_FILENO);  
        dup2(pipe_fd[1],STDERR_FILENO);  
        close(pipe_fd[1]);  
    }
}

答案 1 :(得分:0)

如果您已经实现了C程序并且想要执行脚本,则需要使用fork()。除非您愿意考虑在程序中嵌入脚本解释器,否则必须使用fork()(system()在内部使用fork())。

如果你的资源不足,很可能,你并没有收获你的孩子。在父进程获得退出代码之前,操作系统需要将子进程作为“僵尸”进程。您需要发出wait()调用以让操作系统释放与孩子相关的最终资源。

答案 2 :(得分:0)

一种简单的方法是使用popenhttp://www.opengroup.org/onlinepubs/007908799/xsh/popen.html),它会返回FILE*

答案 3 :(得分:0)

您可以尝试popen(),但您的基本问题是运行过多的进程。你必须确保你的命令完成,否则你最终会遇到你遇到的问题。无论如何popen()内部调用fork()(或效果就像它一样)。

所以,最后,必须确保你想要从你的线程运行的程序“很快”退出。

答案 4 :(得分:0)

你想使用这样的序列:

Call pipe once per stream you want to create (eg. stdin, stdout, stderr)
Call fork
in the child
   close the parent end of the handles
   close any other handles you have open
   set up stdin, stdout, stderr to be the appropriate child side of the pipe
   exec your desired command
   If that fails, die.

in the parent
   close the child side of the handles
   Read and write to the pipes as appropriate
   When done, call waitpid() (or similar) to clean up the child process.

小心阻止和缓冲。当孩子在阅读时被阻止时,您不希望父进程在写入时阻止;确保使用非阻塞I / O或线程来处理这些问题。