手把手带你写一个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     //  %[^\n]---^代表非 []代表字符集,接收所有在\n之前的任意字符
 30     //  %*c---*表示不读入(直接取出缓冲区的下一个字符),%*c的作用是为了丢掉\n
 31     if(scanf("%[^\n]%*c",str)!=1)    
 32     {
 33       getchar();                  //接收失败,吸收返回的EOF
 34     }
 35     //    printf("cmd:[%s]\n",str);
 36 
 37     //2.解析命令
 38     //需要解决的问题:命令分割,存储位置
 39     //空格分割命令,模拟命令行参数存储命令
 40     char* p = str;
 41     char* argv[32] = {NULL};
 42     int argc = 0;
 43     while(*p!='\0')
 44     {
 45       if(*p!=32)
 46       {
 47         //存入一个命令
 48         argv[argc]=p;
 49         argc++;
 50         //走到空格 
 51         while(*p !=32 && *p!='\0')
 52         {
 53           p++;
 54         }
 55         continue;
 56       }
 57       //遇到空格,分割,加结束标志
 58       else
 59       {
 60         *p='\0';
 61         p++;
 62       }
 63     }
 64     //查看解析
 65     /*int i=0;
 66       for(i;i<argc;i++)
 67       {
 68       printf("argv[%d]--%s\n",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\n");
 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("\n");
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\n");
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("\n");
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 }

       运行结果展示 :

                                     

                        

                            

                        

      

      

猜你喜欢

转载自www.cnblogs.com/Duikerdd/p/11695138.html