【手把手教你制作一个简易版的shell】

这篇具有很好参考价值的文章主要介绍了【手把手教你制作一个简易版的shell】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 基本框架的搭建😆

为了简便,命令行中的提示符我们可以直接用printf打印,而具体执行命令可以交给子进程去做,现在的关键是如何将获得的命令行中的命令切割。我们在学习C语言时提到了strtok函数,正好这个函数可以用来作为切割。
  int Transfor(char commend[],char* arg[])
  {
      arg[0]=strtok(commend,SEP);
      if(arg[0]==NULL)
          return 1;
      int i=1;
      while(arg[i++]=strtok(NULL,SEP));
      return 0;
  }

基本框架:

  int main()
  {
    char myenv[MAX][MAX]={0};
    while(1)
    {
      char commend[MAX];
      char* arg[MAX_NUM];
      printf("[lisi@VM-8-12-centos lesson11]$ ");
      fflush(stdout);                                                                                                                                          
  
      char*str=fgets(commend,sizeof(commend),stdin);
      if(str==0) continue;
      commend[strlen(commend)-1]='\0';
  
      Transfor(commend,arg);
      pid_t id=fork();
      if(id==0)
      {
        //child
        execvp(arg[0],arg);
      }
      //parent
      int status=0;
      pid_t pid=waitpid(id,&status,0);
  }
    return 0;
  }

不知道大家注意到了没有,我们从键盘中读取数据时也将\n读进了字符串中,所以我们直接将\n替换成\0.


2 基本功能的完善😆

2.1 ls

基本逻辑是直接根据execvp函数进行程序替换,但是为了拥有系统的配色方案我们可以在指针数组末尾加一个--color=auto
     if(strcmp(arg[0],"ls")==0)
      {
        int pos=0;
        while(arg[pos]) pos++;
        arg[pos++]=(char*)"--color=auto";
        arg[pos]=NULL;
      }

2.2 cd

在讲述这个命令之前先问一句大家我们通过cd命令切换目录是切换的是父进程的还是子进程的?答案显然是父进程的,所以此时我们并不能通过子进程的程序替换来帮助我们完成工作,要通过系统提供的chdir来帮助我们。

通过man手册我们可以清楚的看见chdir的基本用法:

【手把手教你制作一个简易版的shell】
     else if(strcmp(arg[0],"cd")==0)
      {                   
        if(arg[1]!=NULL) chdir(arg[1]);
        continue;                                                         
      }

像上面这种让bash自己执行的任务我们称之为内建命令/内置命令。

2.3 export

同样的我们导入环境变量时我们想的是将环境变量导给父进程,这样子进程也能够继承父进程的环境变量,但是如果我们只是单纯的将arg中的环境变量通过putenv导入的话会出现问题的,因为我们每次执行新的命令时arg中的内容都会发生改变,也就是其实arg是一个随时有可能被修改的指针数组,这时你导入的结果就可能会出现差错,解决方法是通过自己再定义一个专门存放环境变量的数组中,然后在putenv进去。 一般用户自定义的环境变量,在bash中要用户自己来进行维护,不要用一个经常被覆盖的缓冲区来保存环境变量。
     else if(strcmp(arg[0],"export")==0)
      {
        if(arg[1]!=NULL)
        {
          strcpy(myenv[envi],arg[1]);
          putenv(myenv[envi++]);
        }
        continue;
      }

2.4 env

这个命令其实还是查看的是父进程的环境变量表,其实我们学过的大多数关于环境变量的命令几乎都是内建命令,为了演示效果更加明显我们可以自己封装一个打印函数。
  
  void showEnv()
  {
    extern char** environ;
    int i=0;
    for(;environ[i];i++) printf("%d:%s\n",i+1,environ[i]);
  }
     
    else if(strcmp(arg[0],"env")==0)
      {
        showEnv();
        continue;
      }

2.5 echo

     else if(strcmp(arg[0],"echo")==0)
      {
        char* targrt_env=NULL;
        if(arg[1][0]=='$')
        {
          if(arg[1][1]=='?')
          {
            printf("%d\n",last_exit);
            continue;                                                                                                                       
          }
          else{
          targrt_env=getenv(arg[1]+1);
          }
          if(targrt_env!=NULL)
            printf("%s=%s\n",arg[1]+1,targrt_env);
        }
        continue;
      }

在上面我们可以通过echo $?拿到最近的一次退出码,也能够打印出我们想要查看的环境变量的值是多少。


3 源代码😆

  #include<stdio.h>
  #include<string.h>
  #include<stdlib.h>
  #include<assert.h>
  #include<sys/types.h>
  #include<sys/wait.h>
  
  
  #define MAX 1024
  #define MAX_NUM 64
  #define SEP " "
  int Transfor(char commend[],char* arg[])
  {
      arg[0]=strtok(commend,SEP);
      if(arg[0]==NULL)
          return 1;
      int i=1;
      while(arg[i++]=strtok(NULL,SEP));
      return 0;
  }
  
  void showEnv()
  {                                                                                                                                         
    extern char** environ;
    int i=0;
    for(;environ[i];i++) printf("%d:%s\n",i+1,environ[i]);
  }
  int main()
  {
    int last_exit=0;
    char myenv[MAX][MAX]={0};
    int envi=0;
    while(1)
    {
      char commend[MAX];
      char* arg[MAX_NUM];                                                                                                                   
      printf("[lisi@VM-8-12-centos lesson11]$ ");
      
      fflush(stdout);
      
      char*str=fgets(commend,sizeof(commend),stdin);
      if(str==0) continue;
      commend[strlen(commend)-1]='\0';
      
      Transfor(commend,arg);
      if(strcmp(arg[0],"ls")==0)
      {
        int pos=0;
        while(arg[pos]) pos++;
        arg[pos++]=(char*)"--color=auto";
        arg[pos]=NULL;
      }
      else if(strcmp(arg[0],"cd")==0)
      {
        if(arg[1]!=NULL) chdir(arg[1]);
        continue;
      }
      else if(strcmp(arg[0],"export")==0)
      {
        if(arg[1]!=NULL)
        {
          strcpy(myenv[envi],arg[1]);
          putenv(myenv[envi++]);                                                                                                            
        }
        continue;
      }
      else if(strcmp(arg[0],"env")==0)
      {
        showEnv();
        continue;
      }
      else if(strcmp(arg[0],"echo")==0)
      {
        char* targrt_env=NULL;
        if(arg[1][0]=='$')
        {
          if(arg[1][1]=='?')
          {
            printf("%d\n",last_exit);
            continue;
          }
          else{
          targrt_env=getenv(arg[1]+1);
          }
          if(targrt_env!=NULL)
            printf("%s=%s\n",arg[1]+1,targrt_env);
        }                                                                                                                                   
        continue;
      }
      pid_t id=fork();
      if(id==0)
      {
        //child
        execvp(arg[0],arg);
      }
      //parent
      int status=0;
      pid_t pid=waitpid(id,&status,0);
      if(pid>0)
      {
        last_exit=WEXITSTATUS(status);
      }
  }
    return 0;
  }

演示效果:

ls pwd cd:

【手把手教你制作一个简易版的shell】

clear export env:

【手把手教你制作一个简易版的shell】
【手把手教你制作一个简易版的shell】

echo:

【手把手教你制作一个简易版的shell】

好了今天的分享就到这里了,如果对你有帮助的话能不能一键三联博主😚😚😚文章来源地址https://www.toymoban.com/news/detail-415126.html

到了这里,关于【手把手教你制作一个简易版的shell】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【pgzero】手把手教你制作游戏——Pong

    今天要做的游戏叫Pong,它是世界上第一款街机游戏。 (关键它好做) 制作游戏的引擎有很多,比如 Unity 、 Construct . . . . . . ...... ...... 而今天我们用的既不是Unity,也不是Construct,而是 Python 。 制作游戏的模块是 pgzero ,它是在 Python 比较有名的库 Pygame 上又加了一层封装,对

    2024年03月24日
    浏览(26)
  • [Linux]手把手教你制作进度条小程序

    C语言中字符分为两种: 可显字符 控制字符 其中可显字符就是字符a这类的字符,控制字符就是n这种控制字符。 对于我们制作进度条,我们只需要关注两个控制字符: r – 进行回车操作 n – 进行换行加回车操作 说明: n本身是换行字符,但是C语言本身将其解析成了换行加回

    2024年02月14日
    浏览(27)
  • 若依ruoyi——手把手教你制作自己的管理系统【二、修改样式】

    阿里图标一( ̄︶ ̄*)) 图片白嫖一((* ̄3 ̄)╭ ********* 专栏略长 ==== 爆肝万字 ==== 细节狂魔 ==== 请准备好一键三连 ********* 运行成功后: idea后台正常先挂着 我习惯用VScode操作 当然如果有两台机子 一个挂后台一个改前端就更好了 只需修改 vue.config.js 配置文件即可 eg:按 Win+R 打

    2024年02月03日
    浏览(26)
  • 若依ruoyi——手把手教你制作自己的管理系统【三、代码生成】

    增删改查导一( ̄︶ ̄*)) 按钮换个色一((* ̄3 ̄)╭ ********* 专栏略长 ==== 爆肝万字 ==== 细节狂魔 ==== 请准备好一键三连 ********* 修改后的页面: 干干净净贼舒服一Ψ( ̄∀ ̄)Ψ——Ψ( ̄∀ ̄)Ψ一 接下来我们要达到的效果如下(自定义菜单 里面有列表数据回显+增删改查) 一、修改

    2023年04月25日
    浏览(23)
  • 手把手教你制作一块Linux开发板(基于Planck-pi)

    攻城狮星河:Hello,各位野生钢铁侠们! 这篇文章初衷是帮助想自己制作linux小板子的小白们,文中会讲的比较基础,大佬勿喷~ 本教程会以稚晖君开源的 planck-pi 为基础,从0开始手把手教学直到成功复刻 Planck-pi复刻互助群:287810522 提示:以下是本篇文章正文内容,下面案例

    2024年02月01日
    浏览(26)
  • 手把手教你实现一个循环队列(C语言)

    这是一道leetcode关于队列的经典题: 622. 设计循环队列 https://leetcode.cn/problems/design-circular-queue/  大家注意这个题目要求,这个队列是定长的,如果满了则不能再添加数据。那么我们设计一个队头front和队尾rear,每次添加数据rear向后走,这时就有一个问题, 怎么区分空和满呢

    2024年02月04日
    浏览(38)
  • 手把手教你搭建一个Minecraft 服务器

    这次,我们教大家如何搭建一个我的世界服务器 首先,我们来到这个网站 MCVersions.net - Minecraft Versions Download List MCVersions.net offers an archive of Minecraft Client and Server jars to download, for both current and old releases! https://mcversions.net/   在这里,我们点击对应的版本,从左到右依次是稳定版

    2024年02月09日
    浏览(24)
  • 手把手教你做一个多路灰度传感器

    市面上有的灰度传感器对于一些人来说可能不合适  于是呢不少人想自己做,比如我,当时也是走了一些弯路的,现在把自己的经验写上来,各位动手能力强的自己拿去用 原理: 左边发射红外光,地面反射到光敏三极管,改变A_OUTx处的电压值,不同颜色和材质对反射回来的

    2024年02月15日
    浏览(27)
  • 手把手教你用MindSpore训练一个AI模型!

    首先我们要先了解深度学习的概念和AI计算框架的角色( https://zhuanlan.zhihu.com/p/463019160 ),本篇文章将演示怎么利用MindSpore来训练一个AI模型。和上一章的场景一致,我们要训练的模型是用来对手写数字图片进行分类的LeNet5模型 请参考( http://yann.lecun.com/exdb/lenet/ )。 图1 M

    2024年02月04日
    浏览(25)
  • 手把手教你新建一个winform项目(史上最全)

    最近有粉丝订阅了我的博客专栏《winform控件从入门到精通》,但是却来问我平时使用什么软件来开发winform程序,我本以为订阅我专栏的粉丝至少应该是掌握Microsoft Visual Studio的基本用法,也能够创建winform项目,看来是我大意了,我的错,粉丝们!对于不会创建winform项目但是

    2024年02月04日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包