在开始代码之前,先来普及一下什么是Shell. Shell英文又称壳层.在计算机中,是指"提供用户使用界面"的"系统"软件,通常指的是命令行界面的命令解析器.一般来说,这个词是指操作系统中,提供访问内核所提供之服务的程序.不过这个词也拿来指应用软件,或是任何在特定组件外围的"软件"...省略300字.....
常用的Shell分类:
-
-
bash: 是GNU的Bourne Again Shell,是GNU操作系统上默认的Shell
-
Korn Shell: 是对Bourne Shell的发展,在大部分内容上与Bourne Shell(Bash)兼容
-
C Shell: 是SUN公司Shell的BSD版本
-
Z Shell: Z是最后一个字母,也就是终极Shell.它集成了Bash ksh的重要特性,同时又增加了自己独有的特性.
-
来看看Shell在计算机硬件和软件中的位置
-
直接上代码.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/wait.h>#include <sys/types.h>#include <fcntl.h>#include <sys/stat.h>#include <errno.h>typedefstruct__Info{charbuf[1024];//用户输入信息unsignedintpipeNum;//统计管道的个数}Info;//记录主机名 默认localhoststaticcharhostname[1024] ="localhost";//错误提示intsys_err(constchar* err){perror(err);exit(EXIT_FAILURE);}//消息提示voiddisplay(){staticunsignedintsum = 1;//记录输入次数charbuf[1024] = { 0 };//获取当前路径getcwd(buf,sizeof(buf));sum++;}/** 用户输入的内容处理* @reminder info 传入的结构体* return:* 成功:EXIT_SUCCESS* 失败:EXIT_FAILURE*/inthandle(Info* info){if(NULL == info){printf("func %s err: [NULL == info]\n", __FUNCTION__);exit(EXIT_FAILURE);}char* p = info->buf;//统计管道的个数while(NULL != (p =strchr(p,'|'))){info->pipeNum++;p++;}p = info->buf;//去除回车if(NULL != (p =strchr(p,'\n'))){*p ='\0';}returnEXIT_SUCCESS;}//字符替换intreplate(char* str,constcharsrc,constchardes){if(NULL == str){printf("func %s error: [NULL == str]\n", __FUNCTION__);exit(EXIT_FAILURE);}char* p =str;while(*p){if(src == *p){*p = des;}p++;}returnEXIT_SUCCESS;}//命令解析intresolveRun(char* ptr,char** argv){if(NULL == ptr || NULL == argv){printf("func %s error:[NULL == ptr || NULL == argv]\n", __FUNCTION__);exit(EXIT_FAILURE);}inti = 0;intfd;char* inptr = NULL;char* p = strtok_r(ptr," ", &inptr);argv[i++] = p;while(NULL != (p = strtok_r(NULL," ", &inptr))){argv[i++] = p;}//判断是否有重定向i--;while(i){if(0 ==strcmp(argv[i],">")){fd = open(argv[i+1], O_WRONLY | O_CREAT | O_TRUNC, 0644);if(0 > fd){sys_err("func resolveRun() open error: ");}//备份输出至1023描述符dup2(STDOUT_FILENO, 1023);dup2(fd, STDOUT_FILENO);argv[i] = NULL;close(fd);//找到第一个>intn = 1;while(n < i){if(0 ==strcmp(argv[n],">")){argv[n] = NULL;break;}n++;}break;}if(0 ==strcmp(argv[i],">>")){fd = open(argv[i+1], O_APPEND|O_CREAT|O_WRONLY, 0644);if(0 > fd){sys_err("func resolveRun() open error: ");}dup2(STDOUT_FILENO, 1023);dup2(fd, STDOUT_FILENO);argv[i] = NULL;close(fd);//找到第一个>intn = 1;while(n < i){if(0 ==strcmp(argv[n],">>")){argv[n] = NULL;break;}n++;}break;}if(0 ==strcmp(argv[i],"<")){fd = open(argv[i+1], O_RDONLY);if(0 > fd){sys_err("func resolveRun() open error: ");}charbuf[1024] = { 0 };intlen = 0;while(0 != (len = read(fd, buf,sizeof(buf)))){if(0 > len){sys_err("func resolveRun() read error: ");}write(STDIN_FILENO, buf, len);bzero(buf,sizeof(buf));}//向末尾输出一个结束符-1putc(-1, STDIN_FILENO);argv[i] = NULL;close(fd);//找到第一个>intn = 1;while(n < i){if(0 ==strcmp(argv[n],"<")){argv[n] = NULL;break;}n++;}break;}i--;}returnEXIT_SUCCESS;}//拆分命令intseve(Info* info){if(NULL == info){printf("func %s err: [NULL == info]\n", __FUNCTION__);exit(EXIT_FAILURE);}//判断是否为空数据if(0 == *(info->buf)){returnEXIT_SUCCESS;}pid_t pid;pid_t wpid;charbuf[1024] = { 0 };char* p = buf;char* inptr = NULL;inti = 0;intfd[2];char* argv[256] = {NULL};//复制原有数据memcpy(buf, info->buf,sizeof(buf));//处理tab键replate(buf,'\t',' ');//处理'号replate(buf,'\'',' ');//处理"号replate(buf,'\"',' ');for(i = 0; i <= info->pipeNum; i++){if(0 == i){p = strtok_r(p,"|", &inptr);}else{p = strtok_r(NULL,"|", &inptr);}//初始化bzero(argv,sizeof(argv));//命令解析resolveRun(p, argv);//判断是否是内置命令if(0 == i && 0 ==strcmp("cd", argv[0])){if(0 > chdir(argv[1])){//判断错误类型,提示用户信息if(ENOENT ==errno){printf("-sea_bash: cd: %s: 没有那个文件或目录\n", argv[1]);}if(EACCES ==errno){printf("-sea_bash: cd: %s: 权限不够\n", argv[1]);}if(ENOTDIR ==errno){printf("-sea_bash: cd: %s: 不是目录\n", argv[1]);}}returnEXIT_SUCCESS;}elseif(0 == i && 0 ==strcmp("pwd", argv[0])){charbuf[1024] = { 0 };getcwd(buf,sizeof(buf));//获取当前工作目录buf[strlen(buf)] ='\n';//末尾添加换行write(STDOUT_FILENO, buf,strlen(buf));//向屏幕打印当前路径returnEXIT_SUCCESS;//成功结束}elseif(0 == i && 0 ==strcmp("hostname", argv[0])){//清空bzero(hostname,sizeof(hostname));//将原来的hostname清空memcpy(hostname, argv[1],strlen(argv[1]));//重新设置hostnamereturnEXIT_SUCCESS;}elseif(0 == i && 0 ==strcmp("exit", argv[0])){//结束进程printf("--------------------god-bey-----------------------------\n");kill(getpid(), SIGINT);//向本进程发送结束信号exit(EXIT_SUCCESS);//直接进程退出}//创建管道if(0 > pipe(fd)){sys_err("func seve() pipe error: ");}pid = fork();if(0 > pid){sys_err("func seve() fork error:");}elseif(0 == pid){close(fd[0]);//子进程关闭读端dup2(1022, fd[0]);//将上一个管道的读端重定向到fd[0]close(1022);//关闭1022上一个信号的读端,避免多个读端存在break;//跳出}//还原输出描述符dup2(1023, STDOUT_FILENO);//保存读端给下一个进程使用dup2(fd[0], 1022);close(fd[1]);close(fd[0]);}//子进程处理if(i != info->pipeNum+1){//没有管道命令if(0 != info->pipeNum){if(i == info->pipeNum){close(fd[1]);dup2(fd[0], STDIN_FILENO);}if(0 == i){dup2(fd[1], STDOUT_FILENO);}else{dup2(fd[0], STDIN_FILENO);dup2(fd[1], STDOUT_FILENO);}}execvp(argv[0], argv);printf("-sea_bash: %s: command not found\n", argv[0]);exit(EXIT_FAILURE);}//父进程等待子进程结束if(i == info->pipeNum+1){do{wpid = waitpid(-1, NULL, WNOHANG);if(0 < wpid){i--;}}while(0 < i);}returnEXIT_SUCCESS;}intmain(intargc,char* argv[]){Info info = {{0}, 0};for(;;){display();//获取用户输入fgets(info.buf,sizeof(info.buf), stdin);//信息处理handle(&info);//拆分命令seve(&info);//清空初始化bzero(&info,sizeof(info));}returnEXIT_SUCCESS;}
本文转自asd1123509133 51CTO博客,原文链接:http://blog.51cto.com/lisea/1788046,如需转载请自行联系原作者