【问题标题】:C - pipe without using popenC - 不使用 popen 的管道
【发布时间】:2013-11-09 03:22:27
【问题描述】:

我怎样才能改变这个:

FILE *f;
char in_buffer[80];
f=popen("command","r");
fgets(in_buffer,sizeof(in_buffer),f)

不使用popen(),而只使用pipe()或其他指令?

【问题讨论】:

  • forkexecvedup2openclose。查找它们。
  • 没有作业。只是想知道 popen 到底做了什么以及如何用管道实现它

标签: c pipe popen


【解决方案1】:

这是我的简单实现,用 cmets 解释正在做什么。

#include <unistd.h>
#include <stdio.h>

FILE *
my_popen (const char *cmd)
{
    int fd[2];
    int read_fd, write_fd;
    int pid;               

    /* First, create a pipe and a pair of file descriptors for its both ends */
    pipe(fd);
    read_fd = fd[0];
    write_fd = fd[1];

    /* Now fork in order to create process from we'll read from */
    pid = fork();
    if (pid == 0) {
        /* Child process */

        /* Close "read" endpoint - child will only use write end */
        close(read_fd);

        /* Now "bind" fd 1 (standard output) to our "write" end of pipe */
        dup2(write_fd,1);

        /* Close original descriptor we got from pipe() */
        close(write_fd);

        /* Execute command via shell - this will replace current process */
        execl("/bin/sh", "sh", "-c", cmd, NULL);

        /* Don't let compiler be angry with us */
        return NULL;
    } else {
        /* Parent */

        /* Close "write" end, not needed in this process */
        close(write_fd);

        /* Parent process is simpler - just create FILE* from file descriptor,
           for compatibility with popen() */
        return fdopen(read_fd, "r");
    }
}

int main ()
{
    FILE *p = my_popen ("ls -l");
    char buffer[1024];
    while (fgets(buffer, 1024, p)) {
        printf (" => %s", buffer);
    }
    fclose(p);
}

注意事项:

  1. 第三代代码仅支持popen"r" 模式。实现其他模式,即"w" 模式留给读者练习。
  2. 本示例中使用的系统函数可能会失败 - 错误处理留给读者练习。
  3. pclose 的实现留给读者作为练习 - 请参阅 closewaiptidfclose

如果您想查看真正的实现,可以查看OSXGNU glibcOpenSolaris 等的来源。

希望这会有所帮助!

【讨论】:

  • close(1); 是不必要的,因为dup2() 会在需要时这样做。 OTOH,在dup2() 之后close(write_fd) 可能有用...
  • 你能解释一下:dup2(write_fd,1);的意思吗? ?
  • 根据标准,文件描述符 1 是标准输出。默认情况下,它连接到某种终端。另一方面,write_fd 是连接子进程和父进程的管道的可写端。我们希望任何发送到 fd 1 的东西都通过创建的管道而不是终端进入我们的父进程,所以调用 dup2 是必要的。详情请见man dup2
  • 注意:fork() 将在出错时返回 -1。这个应该处理!
  • @johannes 见注释 #2
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-16
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 2011-11-15
相关资源
最近更新 更多