今天我写了一个简单的shell 按照github上面的ish 写的
shell 的特征
输入一行 输出一行
可以一直输入 输出 输入 输出
输入exit 或 ctrl-c 会退出
输入命令 输出结果
shell 的组成 可以认为shell 是一无线循环中 遇到exit 和 ctrl-c 退出 需要读取数据和解析数据 执行数据
我们可以分为几个函数 1.无限运行shell的函数 2.读取一行用户输入的函数 3.解析输入的函数 4.执行输入的数据
无限运行shell的函数 1.while循环 2.输出’>’ 3.读取一行的数据 4.解析一行的数据 5.执行一行的数据 如何判断需要退出呢? 设置一个状态status 为0的时候退出 为1的时候继续 如何存储一行输入的数据呢? 使用char* line 如何存储解析完的数据呢? 使用char** tokens 循环一次 free一次
读取一行用户输入的函数 用户输入一行的数据 读取一行的数据 返回一行的数据
解析一行的数据 将一行的输入按照空格进行分开解析成
1 2 tokens[0 ]="ls" ; tokens[1 ]="-al"
执行输入的数据 使用fork 和 exec 执行 执行成功返回1 结束返回0 错误返回-1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> void lsh_loop (void ) ;char *lsh_read_line (void ) ;char **lsh_splite_line (char *line) ;int lsh_launch (char **args) ;int lsh_execute (char **args) ;int lsh_cd (char **args) ;int lsh_help (char **args) ;int lsh_exit (char **args) ;int lsh_num_builtins (void ) ;char *builtin_str[]= { "cd" , "help" , "exit" }; int (*builtion_func[])(char **)= { &lsh_cd, &lsh_help, &lsh_exit }; int main (int argc,char **argv) { lsh_loop(); return EXIT_SUCCESS; } void lsh_loop () { char *line; char **args; int status; do { printf (">" ); line = lsh_read_line(); args = lsh_splite_line(line); status = lsh_execute(args); free (line); free (args); } while (status); } char *lsh_read_line (void ) { char *line = NULL ; ssize_t bufsize = 0 ; if (getline(&line,&bufsize,stdin )==-1 ) { if (feof(stdin )) { exit (EXIT_SUCCESS); } else { perror("lsh: getline\n" ); exit (EXIT_FAILURE); } } return line; } #define LSK_TOK_BUFSIZE 64 #define LSK_TOK_DELIM " \t\r\n\a" char **lsh_splite_line (char *line) { int bufsize = LSK_TOK_BUFSIZE; int position =0 ; char **tokens = malloc (bufsize*sizeof (char *)); char *token; if (!tokens) { perror("lsh: allocation error\n" ); exit (EXIT_FAILURE); } token = strtok(line, LSK_TOK_DELIM); while (token!=NULL ) { tokens[position]=token; position++; if (position>bufsize) { bufsize += LSK_TOK_BUFSIZE; tokens =realloc (tokens, sizeof (bufsize*sizeof (char *))); if (!tokens) { perror("Lsh: allocation error\n" ); exit (EXIT_FAILURE); } } token = strtok(NULL , LSK_TOK_DELIM); } tokens[position] = NULL ; return tokens; } int lsh_launch (char **args) { pid_t pid,wpid; int status; pid=fork(); if (pid==0 ) { if (execvp(args[0 ],args)==-1 ) { perror("lsh" ); } } else if (pid<0 ) { perror("lsh: fork error\n" ); } else { do { wpid = waitpid(pid,&status,WUNTRACED); } while (!WIFEXITED(status)&&!WIFSIGNALED(status)); } return 1 ; } int lsh_execute (char **args) { if (args[0 ]==NULL ) { return 1 ; } for (int i=0 ;i<lsh_num_builtins();i++){ if (strcmp (args[0 ],builtin_str[i])==0 ) { return (*builtion_func[i])(args); } } return lsh_launch(args); } int lsh_cd (char **args) { if (args[1 ]==NULL ) { fprintf (stderr ,"lsh: expected argument to \"cd\"\n" ); } else { if (chdir(args[1 ])!=0 ) { perror("lsh" ); } } return 1 ; } int lsh_exit (char **args) { return 0 ; } int lsh_num_builtins () { return sizeof (builtin_str) / sizeof (char *); } int lsh_help (char **args) { printf ("This is a simple shell" ); printf ("This following are built in:" ); for (int i=0 ; i<lsh_num_builtins(); i++) { printf ("%s\n" ,builtin_str[i]); } printf ("Use the man command for information on other programs.\n" ); return 1 ; }
后记