Linux Shell中管道的原理及C实现框架

在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}'
这句命名的作用非常简单,
- 通过
grep命令在minicom.log中检索含有error关键字的行 - 通过
awk命令打印grep的输出结果中每一行的第一个字段
在Shell中要实现这样的效果,有4个步骤:
- 创建pipe
- fork两个子进程执行grep和awk命令
- 把grep子进程的标准输出、标准错误重定向到管道数据入口
- 把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实现框架的更多相关文章
- Linux Shell中的特殊符号和含义简明总结(包含了绝大部份)
case语句适用于需要进行多重分支的应用情况. case分支语句的格式如下: case $变量名 in 模式1) 命令序列1 ;; 模式2) 命令序列2 ;; *) 默认执行的命令序列 ...
- linux Shell中常用的条件判断
linux Shell中常用的条件判断 -b file 若文件存在且是一个块特殊文件,则为真 -c file 若文件存在且是一个字符特殊文件,则为真 -d ...
- linux shell 中的sleep命令
开始还以为是这样的语法: sleep(1), 后面发现是: linux shell 中的sleep命令 分类: LINUX 在有的shell(比如linux中的bash)中sleep还支持睡眠(分,小 ...
- 理解 Linux shell 中的一个方言:2>&1
理解 Linux shell 中的一个方言:2>&1 2016-11-14 杜亦舒 前言 在使用 linux 命令或者 shell 编程时,这个用法常会遇到 2>&1 如 ...
- linux shell 中的位置变量
对于linux shell 中的位置变量,我一直以来都是吐不出来又咽不下去,每次看到都不懂,不懂了就去百度google,看完了又忘,真是慢性咽炎啊.现在认真想想也是,其实自己一直以来都没有好好学习过, ...
- Linux shell中的一个问题 ${}带正则匹配的表达式
目前在准备龙芯项目的PMON,在研究其编译过程的时候,看到一些make 语句,百思不得其解.后来在shell编程中看到一点资料,牵扯到Shell中的正则表达式.故记录下来,以备后来查阅. 问题: 在某 ...
- Linux shell中的竖线(|)——…
原文地址:Linux shell中的竖线(|)--管道符号作者:潇潇 管道符号,是unix一个很强大的功能,符号为一条竖线:"|". 用法: command 1 | command ...
- [转载]Linux shell中的竖线(|)——管道符号
原文地址:Linux shell中的竖线(|)--管道符号作者:潇潇 管道符号,是unix一个很强大的功能,符号为一条竖线:"|". 用法: command 1 | command ...
- Linux Shell中有三种引号的用法
Linux Shell中有三种引号,分别为双引号(" ").单引号(' ')以及反引号(` `). 其中双引号对字符串中出现的$.''.`和\进行替换:单引号不进行替换,将字符串中 ...
随机推荐
- 最优化 KKT条件
对于约束优化问题: 拉格朗日公式: 其KKT条件为: 求解 x.α.β 其中β*g(x)为互补松弛条件 KKT条件是使一组解成为最优解的必要条件,当原问题是凸问题的时候,KKT条件也是充分条件.
- loadrunner测试c/s架构的应用系统
用LoadRunner测试c/s架构的软件,怎样去选择协议,困扰了我很久,看到这篇文章,感觉有点收获,所以特意转了过来,希望对大家有用. 首先,什么是协议?协议无非就是一个约定,关于数据包发送的格式的 ...
- fzu_oop_east 第二次作业
这次有四题: 题目1:(这题本身没难度,就是听说格式比较坑,好像) 代码: #include<iostream> #include<cstdio> using namespac ...
- python open 追加
今天操作失误,导致home目录没空间了,结果跑了3天的程序断了,还好代码可以重新运行. 读写的文件使用追加方式: # a # 打开一个文件用于追加(只写),写入内容为str # 如果该文件已存在,文件 ...
- weblogic之CVE-2016-3510反序列化分析
将反序列化的对象封装进了weblogic.corba.utils.MarshalledObject,然后再对MarshalledObject进行序列化,生成payload字节码.由于Marshalle ...
- .net中使用mysql回滚和sqlserver回滚的区别
关于sqlserver事务和mysql事务 首先这是一种方法 public static int GetExecteQuery() { SqlConnection ...
- python过滤文件中特殊标签
Beautiful Soup Beautiful Soup 是用Python写的一个HTML/XML的解析器,它可以很好的处理不规范标记并生成剖析树(parse tree). 它提供简单又常用的导航( ...
- 修改Xcode工程名称
概述 有的时候需要在现有的项目上面开发一个新的项目,如果新建工程的话,就比较麻烦了,所以一般是直接现有的工程上面直接修改名字步骤如下: 1.修改工程名字 在这里修改完之后,会弹出一个对话框,点击Ren ...
- echo图片延迟加载js
插件描述:和 Lazy Load 一样,Echo.js 也是一个用于图像延迟加载 JavaScript.不同的是 Lazy Load 是基于 jQuery 的插件,而 Echo.js 不依赖于 jQu ...
- 获取某商家当前每个月销量sql语句。
用两个mysql函数 FROM_UNIXTIME( ordertime )将日期格式转换成时间戳 month( FROM_UNIXTIME( ordertime ) ) 获取当前日期的月 select ...