开发者社区> 科技小能手> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

UNIX命令行管道机制-UNIX哲学

简介:
+关注继续查看

UNIX从来都不是为人机交互而设计的,而是为程序之间的交互而设计的。

用了多年Linux,从起初的羡慕,崇拜,到初学时的不解,混乱,愤怒,后来失望,困惑,...最终发现,如果你真的非要和Windows相比较的话,UNIX的人机交互确实表现不佳,正是这种不佳才导致了在使用过程中的种种问题,比如愤怒,比如失望...但是当我真正理解了UNIX的设计初衷的时候,这才彻底明白了一些事情的真相。正如Windows拥有那么多的UI元素以及纷繁惹人眼的绚丽控件以获得使用者最大的舒适度一样,UNIX设计了shell管道以获得程序之间交互的最大舒适度。
        UNIX是以小为美的设计典型,和Windows不属于一个理念。但是如果你把UNIX的一个命令理解成Windows界面的一个控件的话,或许会好很多,人们会操作(点击,下拉,拖移...)一个控件以获得一种效果,而UNIX程序也会将输出重新输入给另一个程序以获取一种效果,和Windows不同的是,这个操作一般不需要人的参与,全是程序之间的事情,人的作用往往体现在程序的组织上,程序之间如何来组织,如何来交互,这需要人来告诉UNIX系统-实际上也就是编写一个脚本。
        因此,越小的程序越好,便于人们去组织它们,这样它们的(使用代码行/总体代码行)这个比值是最高的,也正是因此,这个事实浓缩成了UNIX的另一个哲学:小程序只做好一件事。其实,我们发现,这条哲学可以从UNIX终极哲学中衍生出来。程序间的交互远远没有人机交互复杂,我们只需要想一下程序要如何表达自己的功能就可以了,归结于一点,那就是程序必须要有产出,也就是输出,而输入就是其原材料,程序扮演了加工者的角色,也就是一个过滤器,好的程序始终不要自己产生输出,正如没有能源输入,永动机早晚要停一样,程序的输出必须由输入加工而来,而最终的数据来自于人。因此下面的哲学被衍生了出来:
1.程序只是一个过滤器
2.程序之间的交互就是输入和输出

因此管道的概念就被呼出来了!什么是管道?管道就是一个pipe(??!fk!),将一个程序的输出和另一个程序的输入联系起来的一根管子。UNIX的命令行管道如下图所示


将各个程序画成阶梯状完全是为了展示管道,实际上它们都是同时执行的,只是启动先后顺序不同而已,一个命令行可以通过“|”来分隔为多个命令,前面命令的输出作为紧接着后面命令的输入,通过管道彼此相连接。

        这种管道到底是怎么实现的呢?如果看一下shell的源代码,比如csh,bash等,那固然不错,可是却容易被太多的额外处理混淆了视听,你很难从复杂的shell源代码中抽出哪些是和命令行管道相关的,加上代码本身的调用层次很深,看懂代码就更佳困难,除非你专门想研究一下shell的实现,否则如果仅仅想知道命令行管道这么一件简单的事情的话,还是自己实现一个为好。这难道不矛盾吗?你都不知道怎么实现的,怎么自己实现啊?!可是你知道效果啊,你也知道规范,这些就够了,这里又有一个不成文的规则:当你只知道效果和规范的时候,自己动手实现一个符合规范的机制之后,你就会明白该机制是怎么实现的了。
        因此,代码不重要,重要的是设计本身!而设计是属于比较高层面的概念,其下是复杂的逻辑,因此要问程序是什么,程序就是逻辑。
        以下就是自己粗略实现的一个执行命令行管道程序的小shell的代码:
/**  *    简单展示原理,没有错误处理  *    简单展示原理,能用即可  *    这是所谓的“第一个系统”  */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h>  int fork_and_exec(char *cmd, int pin, int pout) {     int pid = fork();     if (pid == 0) {         if (pin != -1) {             dup2 (pin, 0);             close(pin);         }         if (pout != -1) {             dup2 (pout, 1);             close(pout);         }         //exec太麻烦,索性用system了         //但是必须知道system的原理(fork+exec...)         //if (execlp(cmd, NULL) == -1) {         system(cmd); //若是exec且执行成功,就不需要exit了         exit(0);     } else if(pid > 0) {         if (pin != -1)             close(pin);         if (pout != -1)             close(pout);     } else {         //TODO     }     return pid; }  int execute_cmd(char *cmd, int in) {     char *p = cmd;     char *start_cmd = cmd;     int pipefd[2];     while (*p) {         switch (*p) {             case '|':                 *p++ = 0;                 //创建一个管道                 pipe(pipefd);                 //下面的语句执行后,程序分叉,第一叉在当前捕获的命令,第二                 //叉在后面继续解析命令                 //将写管道传给当前捕获的命令用于重定向其stdout                 if (fork_and_exec(start_cmd, in, pipefd[1]) > 0) {                     //将读管道传给将要被捕获的命令用于重定向其stdin                     goto call_forward_pipe_chain;                 }                 break;             default:                 p++;         }     }     fork_and_exec(start_cmd, in, -1);     fflush(stdout);     return 0; call_forward_pipe_chain:     execute_cmd(p, pipefd[0]);     fflush(stdout);     return 0; }  int main(int argc, char **argv) {     while (1) {         char cmd[1024]={0};         int len;         printf("cmd>>");         fflush(stdout);         gets(cmd);         len = strlen(cmd);         if (!strcmp(cmd, "q")) {             fflush(stdout);             printf("done\n");             exit(0);         } else {             execute_cmd(cmd, -1);         }     }     return 0; }

将上述代码编译成mysh之后,执行之:
root@zhaoya-home:~/test# ./mysh 
cmd>>
cmd>>ls /|grep etc
cmd>>etc
cmd>>ls /dev/|grep tty|wc -l
cmd>>69
cmd>>q
done
root@zhaoya-home:~/test# 

以上就是命令行管道的效果。通过使用这种管道的粘合-纵向-加上shell脚本逻辑上的粘合-横向,小巧的UNIX命令就可以结合在一起,完成几乎所有的工作,并且代码利用率极高,高得不可想象啊!如果是一个包罗万象的大程序,每一次你只使用其5%的功能,那么95%的代码将在此次执行中浪费掉,然而小程序互相结合就比较好,由于每个小程序仅仅完成一个功能,因此你只将用到的命令结合在一起即可,提升了代码利用率(UNIX是从小内存时代一路走来的,如今内存都低于白菜价了,却依然勤俭)。

        因此UNIX本质上就是通过粘合小程序而工作的,你可以看到,就算true,false之类的,也是一个合理的命令。



 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1268974


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
x3d
回顾一下Unix哲学
Unix哲学是一些先哲们多方位阐述的,有多种说法。可以概括为以下几点: 模块原则:使用简洁的接口拼合简单的部件。 清晰原则:清晰胜于机巧。 组合原则:设计时考虑拼接组合。 分离原则:策略同机制分离,接口同引擎分离。
597 0
[总结]Unix设计哲学 <<Unix编程艺术>>
转载请注明出处:http://blog.csdn.net/horkychen 学习了第一章关于哲学的部分, 做个汇总.现在对精简设计, 舍弃华而不实是普遍认可的。
914 0
Linux/UNIX 上安装 MySQL
Linux/UNIX 上安装 MySQL
0 0
【Unix/Linux】文档标准
【Unix/Linux】文档标准
0 0
【Unix/Linux 系统管理】本地文档维护
【Unix/Linux 系统管理】本地文档维护
0 0
【Unix/Linux 系统管理】虚拟机与容器之间的对比
【Unix/Linux 系统管理】虚拟机与容器之间的对比
0 0
文章
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载