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 }
posted @ 2021-10-12 18:04  Ghost_Ying  阅读(574)  评论(0)    收藏  举报