在shell中我们经常用到管道,有没考虑过Shell是怎么实现管道的呢?

cat minicom.log | grep "error"

标准输入、标准输出与管道

我们知道,每一个进程都有3个标准的输入输出文件描述符

描述符编号 简介 作用
0 标准输入 通用于获取输入的文件描述符
1 标准输出 通用输出普通信息的文件描述符
2 标准错误 通用输出错误信息的文件描述符

我们还知道,系统调用pipe可以创建无名管道

int pipe(int pipefd[2]);

pipe的作用是创建无名管道,并创建两个文件描述符

文件描述符 作用
pipefd[0] 管道数据出口
pipefd[1] 管道数据入口

Shell实现管道的原理

在上文的基础上,我们再看看Shell如何实现管道的。

Shell中通过fork+exec创建子进程来执行命令。如果是含管道的Shell命令,则管道前后的命令分别由不同的进程执行,然后通过管道把两个进程的标准输入输出连接起来,就实现了管道。

例如

grep "error" minicom.log | awk '{print $1}'

这句命名的作用非常简单,

  1. 通过grep命令在minicom.log中检索含有error关键字的行
  2. 通过awk命令打印grep的输出结果中每一行的第一个字段

在Shell中要实现这样的效果,有4个步骤:

  1. 创建pipe
  2. fork两个子进程执行grep和awk命令
  3. 把grep子进程的标准输出、标准错误重定向到管道数据入口
  4. 把awk子进程的标准输入重定向到管道数据出口

这样就实现了Shell管道:grep把结果输出到管道,awk从管道获取数据

Shell如何用C实现管道

我没研究过Shell的代码,但不妨碍我们从功能倒推实现,如果是我,我会怎么做呢?

int main(int argc, char **argv)
{
while(1) {
int pfds[2];
pid_t cmd1, cmd2;
if ((cmd1 = fork()) < 0) {
...
} else if (cmd1 == 0) { /* child */
/*
* dup2 把 pfds[1](管道数据入口描述符) 复制到 文件描述符1&2
* 实现把cmd1的标准输出和标准错误 输送到管道
*/
dup2(pfds[1], STDOUT_FILENO);
dup2(pfds[1], STDERR_FILENO);
close(pfds[0]);
close(pfds[1]);
exec(cmd1...);
__exit(127);
} if ((cmd2 = fork()) < 0) {
...
} else if (cmd2 == 0) { /* child */
/*
* dup2 把 pfds[0](管道数据出口描述符) 复制到 文件描述符0
* 实现cmd2从管道中读取(cmd1的输出)数据
*/
dup2(pfds[0], STDIN_FILENO);
close(pfds[0]);
close(pfds[1]);
exec(cmd2...);
__exit(127);
}
close(pfds[0]);
close(pfds[1]);
wait(...);
}
}

Linux Shell中管道的原理及C实现框架的更多相关文章

  1. Linux Shell中的特殊符号和含义简明总结(包含了绝大部份)

    case语句适用于需要进行多重分支的应用情况. case分支语句的格式如下: case $变量名 in 模式1) 命令序列1 ;; 模式2) 命令序列2        ;; *) 默认执行的命令序列  ...

  2. linux Shell中常用的条件判断

    linux Shell中常用的条件判断 -b file            若文件存在且是一个块特殊文件,则为真 -c file            若文件存在且是一个字符特殊文件,则为真 -d ...

  3. linux shell 中的sleep命令

    开始还以为是这样的语法: sleep(1), 后面发现是: linux shell 中的sleep命令 分类: LINUX 在有的shell(比如linux中的bash)中sleep还支持睡眠(分,小 ...

  4. 理解 Linux shell 中的一个方言:2>&1

    理解 Linux shell 中的一个方言:2>&1  2016-11-14 杜亦舒 前言 在使用 linux 命令或者 shell 编程时,这个用法常会遇到 2>&1 如 ...

  5. linux shell 中的位置变量

    对于linux shell 中的位置变量,我一直以来都是吐不出来又咽不下去,每次看到都不懂,不懂了就去百度google,看完了又忘,真是慢性咽炎啊.现在认真想想也是,其实自己一直以来都没有好好学习过, ...

  6. Linux shell中的一个问题 ${}带正则匹配的表达式

    目前在准备龙芯项目的PMON,在研究其编译过程的时候,看到一些make 语句,百思不得其解.后来在shell编程中看到一点资料,牵扯到Shell中的正则表达式.故记录下来,以备后来查阅. 问题: 在某 ...

  7. Linux shell中的竖线(|)——…

    原文地址:Linux shell中的竖线(|)--管道符号作者:潇潇 管道符号,是unix一个很强大的功能,符号为一条竖线:"|". 用法: command 1 | command ...

  8. [转载]Linux shell中的竖线(|)——管道符号

    原文地址:Linux shell中的竖线(|)--管道符号作者:潇潇 管道符号,是unix一个很强大的功能,符号为一条竖线:"|". 用法: command 1 | command ...

  9. Linux Shell中有三种引号的用法

    Linux Shell中有三种引号,分别为双引号(" ").单引号(' ')以及反引号(` `). 其中双引号对字符串中出现的$.''.`和\进行替换:单引号不进行替换,将字符串中 ...

随机推荐

  1. codeforces 17C Balance(动态规划)

    codeforces 17C Balance 题意 给定一个串,字符集{'a', 'b', 'c'},操作是:选定相邻的两个字符,把其中一个变成另一个.可以做0次或者多次,问最后可以生成多少种,使得任 ...

  2. scala简介

    1.什么是Scala scala官方网址: http://www.scala-lang.org Scala是一种多范式的编程语言,其设计的初衷是要集成面向对象编程和函数式编程的各种特性.Scala运行 ...

  3. lisp base

    一 .quote lisp 使用s-expr表示数据和代码,通常会将第一项作为函数,而将后续元素当做参数传给第一项进行计算.可以通过quote来进行其他解析,quote可用(‘)表示: ( + 1 1 ...

  4. angularJs的$scope.$apply

    <!DOCTYPE HTML> <html ng-app> <head> <meta http-equiv="Content-Type" ...

  5. 【OpenCV】【MFC】图片、视频、摄像头输入响应【详细图解】

    记住新建项目后,要配置OpenCV环境!参考链接http://blog.csdn.net/zy122121cs/article/details/49180541 做工程搭建框架什么的,基本的要熟练啊. ...

  6. ubuntu卸载virtualbox

    本想在ubuntu下virtualbox,可惜出错了,需要卸载后再安装,只能百度拼凑后再安装: 1.首先是执行删除命令:sudo apt-get remove virtualbox*( 这样就不用去查 ...

  7. 【[HNOI2004]敲砖块】

    非常巧妙的\(dp\)顺序 这道题如果按照最正常的顺序来\(dp\)的话,显然是没有办法做的,后效性太大了 所以我们可以巧妙的改变\(dp\)的顺序 我们注意到一个位置\((i,j)\)要被打到的话就 ...

  8. C# winform 数据库操作知识点总结(干货)

    1.数据库连接及操作 在说数据库操作之前,先说一下数据库连接操作字符串的获取 首先,点击服务器资源管理器,接下来选中数据连接右键点击添加连接,填入你要连接的服务器名称,点击单选框使用SQL Serve ...

  9. [19/04/25-星期四] GOF23_结构型模式(适配器模式、代理模式)

    一.引言 结构模式:核心作用就是从程序的结构上实现松耦合,从而扩大整体的类结构,用来解决更大的问题. 二.适配器模式(adapter) 生活中假设笔记本是标准的USB接口但是外置键盘是圆形接口,这时候 ...

  10. javascrict中innerhtml和innerText的关系

    1.time.innerHTML 就是id为time的标签中所有包含的代码内容 比如 <div id='time'><a href='#'>time</a>< ...