Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1646899
  • 博文数量: 268
  • 博客积分: 8708
  • 博客等级: 中将
  • 技术积分: 3764
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-06 15:58
文章分类

全部博文(268)

文章存档

2014年(1)

2013年(15)

2012年(23)

2011年(60)

2010年(51)

2009年(12)

2008年(59)

2007年(47)

分类: LINUX

2010-12-03 17:56:50

  管道是linux中一个很重要的命令行操作,因为linux的每个命令都以完成一个任务为目的,只有把些命令组合起来才能做复杂的工作,当然这种方式也提供了很大的灵活性。那么bash中的管道是通过什么实现的呢? 先看一个简单的管道的例子:
               
               
                #include unistd.h>
int fd[2];
void run_ls()
{
      dup2(fd[1],1);
     close(fd[0]);
     close(fd[1]);
     execve("/bin/ls",NULL,NULL);
}
void run_wc()
{
      dup2(fd[0],0);
     close(fd[0]);
     close(fd[1]);
     execve("/usr/bin/wc",NULL,NULL);
}
int main()
{
    pipe(fd);
    if(fork()==0)
        run_ls();
    else
        run_wc();
     return 0;
}

    这个程序的执行结果等效于ls|wc,从代码上看,主程序调用pipe来创建一个管道,如下图:

   对fd[1]进行写操作时会把数据写到内核中的pipe对应的buffer中,而对fd[0]进行读操作时,就是从pipe的buf中读取数据,这样就把fd[0]和fd[1]连接成一个"管道".
   继续看main函数中的代码,fork调用创建出子进程,子进程会继承父进程的文件描述符表,创建子进程后管道的状态是:

    两个进程中的fd[0],fd[1]的值是相同的,它们所指向的内核中的表示文件的结构体也是相的。先不看dup2调用,在子进程关闭fd[1],父进程关闭fd[0]后:

这样在子进程和父进程之间就建立起一个管道,子进程向fd[1]写的数据,父进程可以通过读fd[0]读出。再看dup2调用,父进程中又把标准输入对应 的文件结构体复制成了fd[0]对应的,子进程中把标准输出对应的文件结构体复制成了fd[1]对应的,这个结构体中包含了对文件的操作函数。这样子进程 中写0号文件描述符的数据实际就会写到内核中的pipe的buf中,而父进程从1这个文件描述符对应的文件读取数据,现在1已经不再指向标准输出,而是指 向了pipe的buf。
   虽然这个例子很简单,但已经可以说明bash中管道的原理。从上面的分析我们可以看出,linux中创建进程是从父进程"fork"出来,然后再 execve,而不是在创建时就指定它要运行的函数,完成独立地创建,这样天然的进程的继承关系,为管道的实现提供了很大的方便,因为管道的实现利用了子 进程继承父进程的文件描述符表这一特性。
阅读(877) | 评论(0) | 转发(1) |
0

上一篇:tcl 类

下一篇:shell批量操作文件后缀

给主人留下些什么吧!~~