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的命令行管道如下图所示

UNIX命令行管道机制-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("donen");
            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之类的,也是一个合理的命令。

原文链接: https://blog.csdn.net/dog250/article/details/7484102

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

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

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/409136

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月26日 上午11:13
下一篇 2023年4月26日 上午11:14

相关推荐