linux高编进程------支持外部命令的shell实现(glob、strsep、fork)
简单实现一个可以支持外部命令的shell:
/***************************** *功能:实现一个简单的shell *终端:./shell * 可以输入pwd等外部命令测试 * **************************/ /*******包含头文件********/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <string.h> #include <glob.h> /*******提取DELIMS分隔符*******/ #define DELIMS " \t\n" /********创建命令结构体(方便扩展)**********/ struct cmd_st { glob_t globres ; }; /********打印终端的提示*********/ static void prompt(void) { printf("mysh-0.1$ "); } /*********************************** *功能:解析终端输入的命令行 * 参数:line:从终端获取的命令行 * res:解析的命令行(回填) * ********************************/ static void parse(char *line,struct cmd_st *res) { char *tok ; int i = 0 ; while(1) { //1.从终端截取命令字符串(line为指向欲分割的字符串,DELIM为分隔符,函数将返回分隔符前面的字符串,tok将指向分隔符之后的字符串) tok = strsep(&line,DELIMS); //2.如果解析失败跳出循环 if(tok == NULL) break ; //3.当多个分割符连续可能出现空串则继续 if(tok[0] == '\0') continue ; /********************************************************* * 4.取得的每个字符串都应该保存(由于命令长度不确定,所以一定要变长) * 所以用glob中的gl_pathv存储 * flag:GLOB_NOCHECK:如果没有任何内容匹配tok,返回tok * GLOB_APPEND:第一次不追加,以后追加(不加会覆盖) * 存储结果放到res->globres中 * ******************************************************/ glob(tok,GLOB_NOCHECK | GLOB_APPEND*i ,NULL,&res->globres); i = 1 ; } } int main() { //1.如果使用getline,一定要初始化 char *linebuf = NULL ; size_t linebuf_size = 0 ; struct cmd_st cmd ; pid_t pid ; while(1) { //2.打印终端 prompt(); //3.获取字符串 if(getline(&linebuf ,&linebuf_size,stdin) < 0) break; //4.解析字符串,结果放到cmd.globres.gl_pathv中 parse(linebuf,&cmd); if(0){}//内部命令 else { //5.外部命令:创建子进程 pid = fork(); if(pid < 0) { perror("fork()"); exit(1); } //6.子进程用新进程替换当前进程 if(pid == 0) { execvp(cmd.globres.gl_pathv[0],cmd.globres.gl_pathv); perror("execvp"); exit(1); } else { //7.父进程收尸 wait(NULL); } } } exit(0); }