intmain(int argc,char**argv){// Load config files, if any.// Run command loop.lsh_loop();// Perform any shutdown/cleanup.return EXIT_SUCCESS;}
2、Shell 的基本循环
一个简单的处理命令的方法有三个步骤:
从标准输入读取命令
将命令字符串分离为可执行程序和参数
执行命令
voidlsh_loop(void){char*line;char**args;int status;do {printf("> "); line =lsh_read_line(); args =lsh_split_line(line); status =lsh_execute(args);free(line);free(args); } while (status);}
2.1、读取一行输入
从 stdin 中读取一行听起来很简单,但是在 c 语言中可能会很麻烦。你事先并不知道用户会在 shell 中输入多少文本。因此你需要从一个块开始,如果他们超过了这个块,就重新分配更多的空间,这是 c 语言中常用的策略。
#defineLSH_RL_BUFSIZE1024char*lsh_read_line(void){int bufsize = LSH_RL_BUFSIZE;int position =0;char*buffer =malloc(sizeof(char) * bufsize);int c;if (!buffer) {fprintf(stderr,"lsh: allocation error\n");exit(EXIT_FAILURE); }while (1) {// Read a character c =getchar();// If we hit EOF, replace it with a null character and return.if (c == EOF || c =='\n') { buffer[position] ='\0';return buffer; } else { buffer[position] = c; } position++;// If we have exceeded the buffer, reallocate.if (position >= bufsize) { bufsize += LSH_RL_BUFSIZE; buffer =realloc(buffer, bufsize);if (!buffer) {fprintf(stderr,"lsh: allocation error\n");exit(EXIT_FAILURE); } } }}
如果要更改目录,则需要使用函数 chdir,如果你写了一个叫做 cd 的程序改变了目录,它只会改变自己的工作目录,并不会修改当前的目录。
/* Function Declarations for builtin shell commands: */intlsh_cd(char**args);intlsh_help(char**args);intlsh_exit(char**args);/* List of builtin commands, followed by their corresponding functions. */char*builtin_str[]= {"cd","help","exit"};int (*builtin_func[]) (char**) = {&lsh_cd,&lsh_help,&lsh_exit};intlsh_num_builtins() {returnsizeof(builtin_str) /sizeof(char*);}/* Builtin function implementations.*/intlsh_cd(char**args){if (args[1] ==NULL) {fprintf(stderr,"lsh: expected argument to \"cd\"\n"); } else {if (chdir(args[1])!=0) {perror("lsh"); } }return1;}intlsh_help(char**args){int i;printf("Stephen Brennan's LSH\n");printf("Type program names and arguments, and hit enter.\n");printf("The following are built in:\n");for (i =0; i <lsh_num_builtins(); i++) {printf(" %s\n", builtin_str[i]); }printf("Use the man command for information on other programs.\n");return1;}intlsh_exit(char**args){return0;}
2.5、组装内置命令和程序
最后一个缺失部分是实现 lsh_execute,这个函数将启动一个内建函数或一个进程
intlsh_execute(char**args){int i;if (args[0] ==NULL) {// An empty command was entered.return1; }for (i =0; i <lsh_num_builtins(); i++) {if (strcmp(args[0], builtin_str[i])==0) {return (*builtin_func[i])(args); } }returnlsh_launch(args);}