简单实现一个shell
先解释一下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 }
运行结果展示 :