一篇技术文章如今仅仅是理论上讲得天花乱坠,却不能自己撸出东西来,那么它写的再好,也只能算纸上谈兵。继上一篇 《
我们天天都在使用的套套符命令,Shell 在里面到底动了什么手脚?
》收到大量读者粉丝的点赞之后,我觉得很有必要自己来实现一下套套符的功能。这个功能就是实现下面这样的管道通信,可以将多个指令的输入输出串接起来。
我们要使用 Python 语言,因为 Go 和 Java 语言都不支持 fork 函数。最终需要的是下面这张图,这张图很简单,但是为了构造出这张图,是需要费一番功夫的。
程序的代码文件名是 pipe.py,程序的运行形式如下
统计 pipe.py 文件代码中包含 def 单词的个数,输出
指令执行
每一条指令的运行都需要至少携带一个管道,左边的管道或者右边的管道。第一个指令和最后一个指令只有一个管道,中间的指令有两个管道。管道的标识是它的一对读写描述符(r, w)。
图片
左边管道的读描述符 left_pipe[0] 对接进程的标准输入。右边管道的写描述符 right_pipe[1] 对接进程的标准输出。调整完描述符后,就可以使用 exec 函数来执行指令。
图片
进程关系
shell 需要运行多个进程,就必须用到 fork 函数来创建子进程,然后使用子进程来执行指令。
图片
子又生孙,孙又生子,子子孙孙无穷尽也。理论上使用管道可以串接非常多的进程输入输出流。
启动脚本
需要对命令行参数按竖线进行分割得出多条指令,开始进入递归执行
观察进程关系
因为例子中的几条指令执行时间太短,无法通过 ps 命令来观察进程关系。所以我们在代码里加了一句调试用的输出代码,输出当前进程执行的指令名称、进程号和父进程号。
运行脚本时观察输出
从输出中可以明显看出父子进程的关系,第 N 条指令进程是第 N+1 条指令进程的父进程。在 run_cmds 函数中,fork 出子进程后由父进程来负责执行当前指令,剩余的指令交给子进程执行。所以才形成了上面的进程关系。读者可以尝试调整交互执行顺序,让子进程负责执行当前指令,然后再观察输出
图片
你会发现这三个指令进程都共享同一个父进程,这个父进程就是 Python 进程。如上图所示,我们平时使用的 shell 在执行指令的时候形成的进程关系都是这种形式的,这种形式在逻辑结构上看起来更加清晰。
需要上面的完整源代码,请关注下面的公众号,在里面回复「管道」即可得到源码。
领取专属 10元无门槛券
私享最新 技术干货