linux minishell 源码及注释
linux minishell项目
文件列表:main.c 主函数文件
builitin.c (builtin.h) 判断是否含有内部命令的代码
parse.c (parse.h) 进行命令读取,解析及作为其他文件中的函数的入口
init.c (init.h) 进行各个数据的初始化
execute.c (execute.h) 对解析好的命令进行执行操作
def.h 内含用于装载解析完毕后的参数列表以及输对入流,文件名,管道数量等变量的限制
externs.h 将变量声明为全局变量
源码:
main.c:
1 #include "parse.h" 2 #include "init.h" 3 #include "def.h" 4 5 char cmdline[MAXLINE + 1]; /*键盘输入命令的缓冲区,储存来自键盘输入的命令*/ 6 char avline[MAXLINE + 1]; /*储存从cmdline中提取出来的命令参数*/ 7 char *lineptr; /*储存cmdline的头地址,指向cmdline的头元素*/ 8 char *avptr; /*储存avline的头地址,指向avline的头元素*/ 9 10 COMMAND cmd[PIPELINE]; /*储存解析出的命令参数*/ 11 char infile[MAXNAME + 1]; /*储存要写入管道的文件名称*/ 12 char outfile[MAXNAME + 1]; /*储存要写出到文件中的文件名称*/ 13 14 int cmd_count; /*解析出的命令参数的数量*/ 15 int backgnd; /*判断命令为内部命令或外部命令*/ 16 int append; /*判断写入文件的模式*/ 17 int lastpid; /*储存执行管道中最后一个命令进程的进程号*/ 18 19 int main(void) 20 { 21 setup(); /*安装信号*/ 22 shell_loop(); /*进入shell循环*/ 23 return 0; 24 }
-----------------------------------------------------------------------------------------------------------------------
init.c(init.h):
1 #ifndef _INIT_H_ 2 #define _INIT_H_ 3 4 void setup(void); 5 void init(void); 6 7 #endif
1 #include "init.h" 2 #include <stdio.h> 3 #include <signal.h> 4 #include <string.h> 5 #include "externs.h" 6 7 void sigint_handler(int ); 8 9 void init(void)/*对各变量进行初始化*/ 10 { 11 memset(cmd, 0, sizeof(cmd));/*将结构体内部成员的每个字节都填充为0*/ 12 int i; 13 for(i = 0; i < PIPELINE; ++i) 14 { 15 /*初始化管道*/ 16 cmd[i].infd = 0; 17 cmd[i].outfd = 1; 18 } 19 memset(cmdline, 0, sizeof(cmdline)); 20 memset(avline, 0, sizeof(avline)); 21 lineptr = cmdline; /*指向cmdline的首地址*/ 22 avptr = avline; /*指向avline的首地址*/ 23 memset(infile, 0, sizeof(infile)); 24 memset(outfile, 0, sizeof(outfile)); 25 cmd_count = 0; 26 backgnd = 0; 27 append = 0; 28 lastpid = 0; 29 30 printf("[minishell]$"); 31 fflush(stdout); 32 } 33 34 void setup(void) 35 { 36 signal(SIGINT, sigint_handler); /*将SIGINT信号转置为执行sigint_handler函数*/ 37 signal(SIGQUIT, SIG_IGN); /*进程接收到SIGQUIT信号时忽略它*/ 38 } 39 40 void sigint_handler(int sig) 41 { 42 printf("\n[minishell]$ "); 43 fflush(stdout);/*清空缓冲区,打印出信息*/ 44 }
-----------------------------------------------------------------------------------------------------------------------
def.h:
1 #ifndef _DEF_H_ 2 #define _DEF_H_ 3 #include <stdio.h> 4 #include <stdlib.h> 5 6 #define ERR_EXIT(m)\ 7 do\ 8 {\ 9 perror(m);\ 10 exit(EXIT_FAILURE);\ 11 }\ 12 while(0) 13 14 15 #define MAXLINE 1024/*输入行的最大长度*/ 16 #define MAXARG 20 /*每个简单命令的参数最多个数*/ 17 #define PIPELINE 5 /*一个管道中简单命令的最多个数*/ 18 #define MAXNAME 100 /*10重定向文件名的最大长度*/ 19 20 typedef struct command 21 { 22 char *args[MAXARG + 1]; /*解析出的命令参数列表*/ 23 int infd; 24 int outfd; 25 }COMMAND; 26 27 #endif
-----------------------------------------------------------------------------------------------------------------------
externs.h:
1 #ifndef _EXTERNS_H_ 2 #define _EXTERNS_H_ 3 4 #include "def.h" 5 6 extern char avline[MAXLINE + 1]; 7 extern char cmdline[MAXLINE + 1]; 8 extern char *lineptr; 9 extern char *avptr; 10 extern COMMAND cmd[PIPELINE]; 11 extern char infile[MAXNAME + 1]; 12 extern char outfile[MAXNAME + 1]; 13 extern int cmd_count; 14 extern int backgnd; 15 extern int append; 16 extern int lastpid; 17 18 #endif
-----------------------------------------------------------------------------------------------------------------------
builtin.c(builtin.h):
1 #ifndef _BUILTIN_H_ 2 #define _BUILTIN_H_ 3 4 int builtin(void); 5 6 #endif
1 #include "builtin.h" 2 #include "parse.h" 3 #include "externs.h" 4 #include <stdlib.h> 5 #include <stdio.h> 6 7 typedef void (*CMD_HANDLER)(void); 8 9 typedef struct builtin_cmd 10 { 11 char *name; /*内部命令名称*/ 12 CMD_HANDLER handler; 13 }BUILTIN_CMD; 14 15 void do_exit(void); 16 void do_cd(void); 17 void do_type(void); 18 19 BUILTIN_CMD builtins[] = 20 { 21 {"exit", do_exit}, 22 {"cd", do_cd}, 23 {"type", do_type}, 24 {NULL, NULL} 25 };/*内部命令名称及对应函数名*/ 26 27 /*内部命令解析 28 * 返回1表示为内部命令 29 * 0表示不是内部命令*/ 30 31 int builtin() 32 { 33 int i = 0; 34 int found = 0; 35 while(builtins[i].name != NULL) 36 { 37 if(check(builtins[i].name)) 38 { 39 builtins[i].handler(); 40 found = 1; 41 break; 42 } 43 ++i; 44 } 45 return found; 46 } 47 48 void do_exit() 49 { 50 printf("exit\n"); 51 exit(EXIT_SUCCESS); 52 } 53 54 void do_cd() 55 { 56 printf("do_cd ...\n"); 57 } 58 59 void do_type() 60 { 61 printf("do_type ...\n");; 62 }
-------------------------------------------------------------------------------------------------------------------------
execute.c(execute.h):
1 #ifndef _EXECUTE_H_ 2 #define _EXECUTE_H_ 3 4 int execute_disk_command(void); 5 6 #endif
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <sys/types.h> 4 #include <sys/wait.h> 5 #include <linux/limits.h> 6 #include <fcntl.h> 7 #include "execute.h" 8 #include "def.h" 9 #include "externs.h" 10 11 void forkexec(int ); 12 13 int execute_disk_command() 14 { 15 if(cmd_count == 0) 16 { 17 return 0; 18 } 19 if(infile[0] != '\0') 20 { 21 cmd[0].infd = open(infile, O_RDONLY); 22 } 23 if(outfile[0] != '\0') 24 { 25 if(append) 26 { 27 cmd[cmd_count - 1].outfd = open(outfile, O_WRONLY | O_CREAT | O_APPEND, 0666);/*写在文件末端*/ 28 } 29 else 30 { 31 cmd[cmd_count - 1].outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);/*清空文件,从头写入*/ 32 } 33 } 34 if(backgnd == 1) 35 { 36 signal(SIGCHLD, SIG_IGN);/*内部命令则忽略该信号*/ 37 } 38 else 39 { 40 signal(SIGCHLD, SIG_DFL);/*前台作业则默认该信号,回收子进程*/ 41 } 42 int i; 43 int fd; 44 int fds[2]; 45 for(i = 0; i < cmd_count; ++i) 46 { 47 /*不是最后一条命令则创建管道*/ 48 if(i < cmd_count - 1) 49 { 50 pipe(fds); 51 cmd[i].outfd = fds[1]; 52 cmd[i + 1].infd = fds[0]; 53 } 54 forkexec(i); 55 if((fd = cmd[i].infd) != 0) 56 { 57 close(fd); 58 } 59 if((fd = cmd[i].outfd) != 1) 60 { 61 close(fd); 62 } 63 } 64 if(backgnd == 0) 65 { 66 /*前台作业,需要等待管道中最后一个命令退出*/ 67 while(wait(NULL) != lastpid) 68 { 69 ; 70 } 71 } 72 return 0; 73 } 74 75 void forkexec(int i) 76 { 77 pid_t pid; 78 pid = fork(); 79 if(pid == -1) 80 { 81 ERR_EXIT("fork"); 82 } 83 if(pid > 0) 84 { 85 /*父进程*/ 86 if(backgnd == 1) 87 { 88 printf("%d\n", pid); 89 } 90 lastpid = pid; 91 } 92 else if(pid == 0) 93 { 94 /*表示将第一条简单命令的infd重定向至下列目标文件*/ 95 /*当第一条命令试图从标准输入获取数据的时候立即返回EOF*/ 96 if(cmd[i].infd = 0 && backgnd == 1) 97 { 98 cmd[i].infd = open("/cpp/minishell/null", O_RDONLY); 99 } 100 /*将第一个简单命令进程作为进程组组长*/ 101 if(i == 0) 102 { 103 setpgid(0, 0); 104 } 105 /*子进程*/ 106 if(cmd[i].infd != 0) 107 { 108 close(0); 109 dup(cmd[i].infd); 110 } 111 if(cmd[i].outfd != 1) 112 { 113 close(1); 114 dup(cmd[i].outfd); 115 } 116 int j; 117 for(j = 3; j < 1024; ++j)/*最大进程数*/ 118 { 119 close(j); 120 } 121 /*前台作业能够接收SIGINT和SIGQUIT信号*/ 122 /*这两个信号要恢复为默认操作*/ 123 if(backgnd == 0) 124 { 125 signal(SIGINT, SIG_DFL); 126 signal(SIGQUIT, SIG_DFL); 127 } 128 execvp(cmd[i].args[0], cmd[i].args);/*执行命令*/ 129 exit(EXIT_FAILURE); 130 } 131 }
--------------------------------------------------------------------------------
parse.c(parse.h):
1 #ifndef _PARSE_H_ 2 #define _PARSE_H_ 3 4 void shell_loop(void); 5 int read_command(void); 6 int parse_command(void); 7 int execute_command(void); 8 int check(const char * ); 9 10 #endif
1 #include "init.h" 2 #include "externs.h" 3 #include <stdio.h> 4 #include <unistd.h> 5 #include <sys/types.h> 6 #include <sys/wait.h> 7 #include <linux/limits.h> 8 #include <fcntl.h> 9 #include "execute.h" 10 #include "builtin.h" 11 #include "parse.h" 12 13 void get_command(int ); 14 void getname(char *name); 15 void print_command(void); 16 17 18 /* 19 * shell 主循环 20 */ 21 void shell_loop(void) 22 { 23 while(1) 24 { 25 init(); 26 /*获取命令*/ 27 if(read_command() == -1) 28 { 29 break; 30 } 31 /*解析命令*/ 32 parse_command(); 33 //print_command(); 34 /*执行命令*/ 35 execute_command(); 36 } 37 printf("\nexit\n"); 38 } 39 /* 40 * 读取命令 41 * 成功返回0,,失败或读取到文件结束符号返回-1 42 */ 43 44 int read_command(void) 45 { 46 char buf[1024 + 1]; 47 /*按行读取命令,cmdline中包含\n字符*/ 48 if(fgets(cmdline, MAXLINE, stdin) == NULL) 49 { 50 return -1; 51 } 52 return 0; 53 } 54 /* 55 * 解析命令 56 * 成功返回解析到的命令个数,失败返回-1 57 */ 58 int parse_command(void) 59 { 60 if(check("\n")) 61 { 62 return 0; 63 } 64 /*解析第一条简单命令*/ 65 /*判断是否内部命令并执行它*/ 66 if(builtin()) 67 { 68 return 0; 69 } 70 get_command(0); 71 /*判定是否有输入重定向符*/ 72 if(check("<")) 73 { 74 getname(infile); 75 } 76 /*判定是否有管道*/ 77 int i; 78 for(i = 1; i < PIPELINE; ++i) 79 { 80 if(check("|"))
{ 81 get_command(i); 82 } 83 else 84 { 85 break; 86 } 87 } 88 /*判断是否有输出重定向符*/ 89 if(check(">")) 90 { 91 if(check(">")) 92 { 93 append = 1; 94 } 95 getname(outfile); 96 } 97 /*判定是否后台作业*/ 98 if(check("&")) 99 { 100 backgnd = 1; 101 } 102 /*判定命令结束*/ 103 if(check("\n")) 104 { 105 cmd_count = i; 106 return cmd_count; 107 } 108 else 109 { 110 fprintf(stderr, "Command line syntax error\n"); 111 return -1; 112 } 113 return 0; 114 } 115 /* 116 * 执行命令 117 * 成功返回0,失败返回-1 118 */ 119 120 int execute_command(void) 121 { 122 execute_disk_command(); 123 return 0; 124 } 125 /* 126 * 计息简单命令至cmd[i] 127 * 提取cmdline命令参数到avline数组中 128 * 并且将COMMAND结构中的args[]中的每个指针指向这些字符串 129 */ 130 void get_command(int i) 131 { 132 int j = 0; 133 int inword; 134 while(*lineptr != '\0') 135 { 136 while(*lineptr == ' ' || *lineptr == '\t') /*去除空格*/ 137 { 138 *lineptr++; 139 } 140 cmd[i].args[j] = avptr; /*将第i条命令第j个参数指向avptr*/ 141 while(*lineptr != '\0' /*提取参数*/ 142 && *lineptr != ' ' 143 && *lineptr != '\t' 144 && *lineptr != '>' 145 && *lineptr != '<' 146 && *lineptr != '|' 147 && *lineptr != '&' 148 && *lineptr != '\n') 149 { 150 *avptr++ = *lineptr++; /*参数提取至avptr指针所向的数组avline*/ 151 inword = 1; 152 } 153 *avptr++ = '\0'; 154 switch(*lineptr) 155 { 156 case ' ': 157 case '\t': 158 inword = 0; 159 j++; 160 break; 161 case '<': 162 case '>': 163 case '|': 164 case '&': 165 case '\n': 166 if(inword == 0) 167 { 168 cmd[i].args[j] = NULL; 169 return; 170 } 171 return; 172 default:/*for'\0'*/ 173 return; 174 } 175 } 176 } 177 /* 178 * 将lineptr中的字符串与str进行匹配 179 * 成功返回1,lineptr移过所匹配的字符串 180 * 失败返回0,lineptr保持不变 181 */ 182 int check(const char *str) 183 { 184 char *p; 185 while(*lineptr == ' ' || *lineptr == '\t') 186 { 187 lineptr++; 188 } 189 p = lineptr; 190 while(*str != '\0' && *str == *p) 191 { 192 str++; 193 p++; 194 } 195 if(*str == '\0') 196 { 197 lineptr = p; /*lineptr移过所匹配的字符串*/ 198 return 1; 199 } 200 /*lineptr不变*/ 201 return 0; 202 } 203 204 void getname(char *name) 205 { 206 while(*lineptr == ' ' || *lineptr == '\t') 207 { 208 lineptr++; 209 } 210 while(*lineptr != '\0' 211 && *lineptr != ' ' 212 && *lineptr != '\t' 213 && *lineptr != '>' 214 && *lineptr != '<' 215 && *lineptr != '|' 216 && *lineptr != '&' 217 && *lineptr != '\n') 218 { 219 *name++ = *lineptr++; 220 } 221 *name = '\0'; 222 } 223 224 void print_command() 225 { 226 int i; 227 int j; 228 printf("cmd_count = %d\n", cmd_count); 229 if(infile[0] != '\0') 230 { 231 printf("infile = [%s]\n", infile); 232 } 233 if(outfile[0] != '\0') 234 { 235 printf("infile = [%s]\n", outfile); 236 } 237 for(int i = 0; i < cmd_count; ++i) 238 { 239 j = 0; 240 while(cmd[i].args[j] != NULL) 241 { 242 printf("[%s]\n", cmd[i].args[j]); 243 j++; 244 } 245 printf("\n"); 246 } 247 }

浙公网安备 33010602011771号