• 手把手带你写一个minishell


                     先解释一下Shell : Shell是一个功能为命令行解释器的应用程序,连接了用户和Linux内核,让我们能高效和安全地使用Linux内核。

           要写一个minishell,我们要先理解它的过程:

           读取输入->>命令解析->>创建子进程->>(子进程)程序替换->>(父进程)进程等待

          

            代码及注释如下:

      1 //minishell:
      2 //命令行解释器:
      3 //从标准输入读取数据(scanf)    ls -l -a
      4 //ls----运行ls命令----ls命令是一个外部程序
      5 //创建一个进程,让这个进程运行ls程序(程序替换)
      6 //读取输入->>命令解析->>创建子进程->>程序替换->>(父进程)进程等待
      7 #include<stdio.h>
      8 #include<stdlib.h>
      9 #include<unistd.h>
     10 #include<ctype.h>
     11 #include<errno.h>
     12 #include<string.h>
     13 #include<fcntl.h>
     14 #include<sys/wait.h>
     15 
     16 void Minishell()
     17 {
     18   //循环执行
     19   while(1){
     20 
     21     //启动格式
     22     printf("minishell:");
     23     fflush(stdout);
     24     char str[1024]={0};
     25 
     26     //1.读取输入 ls -a
     27     //需要解决的问题: 空格不截断输入
     28     //scanf返回值:成功:赋值数量,失败:EOF 
     29     //  %[^
    ]---^代表非 []代表字符集,接收所有在
    之前的任意字符
     30     //  %*c---*表示不读入(直接取出缓冲区的下一个字符),%*c的作用是为了丢掉
    
     31     if(scanf("%[^
    ]%*c",str)!=1)    
     32     {
     33       getchar();                  //接收失败,吸收返回的EOF
     34     }
     35     //    printf("cmd:[%s]
    ",str);
     36 
     37     //2.解析命令
     38     //需要解决的问题:命令分割,存储位置
     39     //空格分割命令,模拟命令行参数存储命令
     40     char* p = str;
     41     char* argv[32] = {NULL};
     42     int argc = 0;
     43     while(*p!='')
     44     {
     45       if(*p!=32)
     46       {
     47         //存入一个命令
     48         argv[argc]=p;
     49         argc++;
     50         //走到空格 
     51         while(*p !=32 && *p!='')
     52         {
     53           p++;
     54         }
     55         continue;
     56       }
     57       //遇到空格,分割,加结束标志
     58       else
     59       {
     60         *p='';
     61         p++;
     62       }
     63     }
     64     //查看解析
     65     /*int i=0;
     66       for(i;i<argc;i++)
     67       {
     68       printf("argv[%d]--%s
    ",i,argv[i]);
     69       }
     70       */
     71 
     72     //3.创建子进程
     73     int pid=fork();
     74     if(pid<0)
     75     {
     76       perror("pid error");
     77       exit(-1);
     78     }
     79     //4.程序替换
     80     else if(pid==0)
     81     {
     82       //功能 : 重定向 -- 使用dup2改变数据流向
     83       int i;
     84       for(i=0;i<argc;i++)
     85       {
     86         //>    将原本要写入到终端显示的数据,写入到指定的文件中,并清空文件原有内容
     87         if(strcmp(argv[i],">")==0)
     88         {
     89           close(1);
     90           //打开该文件
     91           int fd = open(argv[argc-1],O_CREAT | O_TRUNC | O_RDWR,0664);
     92           if(fd<0)
     93           {
     94             perror("open error
    ");
     95             return;
     96           }
     97 
     98           dup2(fd,1);
     99           //直接写入数据
    100           int len;
    101           for(len=1;len<i;++len)
    102           {
    103             printf("%s ",argv[len]);
    104           }
    105           printf("
    ");
    106           
    107           close(fd);
    108           return;    
    109         }
    110         //>>    将原本要写入到终端显示的数据,追加写入到指定的文件中
    111         if(strcmp(argv[i],">>")==0)
    112         {
    113           close(1);
    114           //打开文件
    115           int fd = open(argv[argc-1],O_CREAT | O_APPEND | O_RDWR,0664);
    116           if(fd<0)
    117           {
    118             perror("open error
    ");
    119             return;
    120           }
    121           dup2(fd,1);
    122           //直接写入数据
    123           int len;
    124           for(len=1;len<i;len++)
    125           {
    126             printf("%s ",argv[len]);
    127           }
    128           printf("
    ");
    129           close(fd);
    130           return;
    131         }
    132       }
    133       //非重定向直接程序替换
    134       execvp(argv[0],argv);
    135       exit(-1);
    136     }
    137     //5.父进程等待子进程退出
    138     waitpid(pid,NULL,0);
    139 
    140 
    141   }    
    142 } 
    143 
    144 int main()
    145 {
    146   Minishell();
    147   return 0;
    148 }

           运行结果展示 :

                                         

                            

                                

                            

          

          

  • 相关阅读:
    【Gerrit】重磅! 2.x 版本升级到 3.x 版本
    【Linux】参数传递之xargs
    Sqlserver账号对应数据库
    限流:计数器、漏桶、令牌桶 三大算法的原理与实战(史上最全)
    C# 运行在ubuntu, linux系统,在linux系统使用HslCommunication组件,.net core发布到ubuntu系统
    使用nmap命令监控远程服务器指定端口状态
    MySQL使用脚本进行整库数据备份【表(结构+数据)、视图、函数、事件】
    MySQL自定义函数与存储过程的创建、使用、删除
    vue响应式的原理
    浏览器渲染机制
  • 原文地址:https://www.cnblogs.com/Duikerdd/p/11695138.html
Copyright © 2020-2023  润新知