• 40多行实现一个非常简单的shell


    简单的shell的实现

    目的:主要就是为了加深对shell的底层原理的理解


    可以通过接口可以获取到这些主机名等等这里直接就用字符串打印了

    • 当我们打开一个c文件默认就打开了三个输入输出流:stdin(标准输入),stdout(标准输出),stderr(标准错误)

    1. 打印提示符


      在这里插入图片描述

    2. 获取命令字符串


      但是只是这样会有一个问题他会读取一个\n,也就是出现了上面的ls -a -l -n下面空了一行,如何去掉这一行呢?

      commed[strlen(commed)-1]='\0';//即可
      //strlen(commed)-1指向的是\n,这里是把\n替换成\0即可解决问题
      
      • 1
      • 2
      • fgets()函数
    3. 解析命令字符串

      • strtok()

      • 解析完成就可以直接创建子进程来运行了

      • 出现这种现象的主要原因是我们通过子进程来执行cd命令,子进程是回退了,可是并不会影响父进程,pwd显示的是当前进程的路径

      • cd这种命令和ls这种命令不一样,cd这种属于内建命令,他是需要父进程来执行的,而不是子进程去执行;其他的属于第三方命令,由子进程执行(/usr/bin下面看到的都是第三方命令)

      • 所以这个程序就需要步骤4

    4. 检测命令是否是需要shell本身执行的,内建命令

      这里就需要一个函数chdir来更改路径

      到这里简易的shell就完成了,有一个小问题,思考一下函数和进程之前有没有相似性呢?—>答案是有的
      exec/exit就像call/return一个C程序有很多函数组成。一个函数可以调用另外一个函数,同时传递给它一些参数。被调用的函数执行一定的
      操作,然后返回一个值。每个函数都有他的局部变量,不同的函数通过call/return系统进行通信。这种通过参数和返回值在拥有私有数据的函数间通信的模式是结构化程序设计的基础
      一个C程序可以fork/exec另一个程序,并传给它一些参数。这个被调用的程序执行一定的操作,然后通过exit(n)来返回值。调用它的进程可以通过wait来获取exit的返回值。

    附代码

    #include
    #include
    #include
    #include
    #include
    #include
    #define NUM 128
    #define NUM_CMD 64
    int main()
    {
      char commed[NUM];
      //我们要先理解,shell要是自己实现他一定是一个死循环的程序,这样才能够不断的读取命令并执行
      //1.就是获取字符串,c语言的获取字符串可以用fgets
      for(;;)
      {
        printf("[xifeng@VM-16-14-centos 简易版的shell]$ ");
        fflush(stdout);
        commed[0]=0;//O(1)时间复杂度清空字符串
        //2.获取字符串
        fgets(commed,NUM,stdin);
        commed[strlen(commed)-1]='\0';//这里是把\n给替换成\0
        //3.解析字符串
        char* argv[NUM_CMD]={NULL};
        argv[0]=strtok(commed," ");
        int i=1;
        while(argv[i]=strtok(NULL," "))
        {
          ++i;
        }
        //读取之后就需要能够解析代码,因为我们解析出来的指令并没有带路径,所以我们能够选用的exec*函数一定需要带p的,而且之前已经用数组获取了参数,则可以直接使用execvp
       //4.但是在运行命令之前需要先判断是否是内建命令
       //如果是cd命令就执行路径切换用父进程来执行
        if(strcmp(argv[0],"cd")==0 && argv[1]!=NULL)//相等,并且带有参数
        {
          chdir(argv[1]);
        }
        if(fork()==0)
        {
          execvp(argv[0],argv);
          exit(1);
        }
        int status=0;
        waitpid(-1,&status,0);
        printf("exit code:%d\n",(status>>8)&0xFF);
       }
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
  • 相关阅读:
    STM32--人体红外感应开关
    (九)socket·NIO socket 实现 服务端广播+客户端群聊 -不限制次序,不限制交互次数
    23111710[含文档+PPT+源码等]计算机毕业设计基于SpringBoot的体育馆场地预约赛事管理系统的设计
    代码随想录Day18 LeetCode235 二叉搜索树的公共祖先 T701二叉搜索树中的插入操作 T140 删除二叉搜索树中的公共节点
    【打工人摸鱼系列】python做皮卡丘桌宠,工作都有效率了呢
    Outlook 邮箱使用技巧
    Element Plus 的 el-icon 到底怎么用?
    在Ubuntu上安装LibRaw
    Google 开源库Guava详解
    Access,Trunk,Hybrid的一些接触知识以及实验
  • 原文地址:https://blog.csdn.net/weixin_52319694/article/details/127987565