自编shell命令解释器
来源:互联网 发布:mac win8.1 iso 下载 编辑:程序博客网 时间:2024/05/16 04:50
通过几个模型学习shell命令解释器,并尝试自己编写简易的shell
一、确定main函数
明确要做的功能,基本确定几个大函数:
void InitialEnv(); //initial environmentvoid PrintSignal(); //print informationvoid GetInput(); int CommandTransform(); //return 1 for errorvoid Clear(); //clear last command
其中,自己做的前面两个函数可以合并(读者可自行优化)
int main(void){ printf("\n Hello my guester!\n"); while(TRUE){ InitialEnv(); //initial comply's emvironment PrintSignal(); //print sth to recognize user to input commands GetInput(); if (strcmp(cmd[0],"exit")==0) //exit { printf("\n Good bye!\n"); break; } if(CommandTransform()) printf("input error: undefined command\n"); Clear(); } return 0;}
大纲完成后自己就开始列写所需的全局变量了:
char *cmds; //commandint cmds_len; //command's lengthchar **cmd; //every commands' wordint cmd_num; //number of commands' wordsint pip; //how many pipes in command
二、功能函数的实现:
先看前两个函数,功能比较简单:
把主机名和当前目录打印一下并打印输入提示符等待输入;代码如下:
void PrintSignal(){ uid_t my_uid; struct passwd *my_info; my_info =getpwuid( getuid() ); char env[50]; getcwd(env,50); printf( "%s=> %s$ ", my_info->pw_name,env); }
其中getpwuid()函数可以得到my_uid的各个属性,在这里使用获得主机名。getcwd()函数用以输出当前目录。
void InitialEnv(){ int i=0; while((cmds = (char*)malloc(sizeof(char)*100))==0); while((cmd = (char**)malloc(sizeof(char*)*20))==0); while(i<20) { while((cmd[i] =(char*)malloc(sizeof(char)*40))==0); i = i + 1; } cmd_num = 0; pip = 0;}
初始化环境函数:为存储指令的字符指针申请动态空间(malloc函数)
将输入存入字符串:
void GetInput(){ int i = 0; int j = 0; //freopen("/dev/tty","r",stdin); gets(cmds); while (cmds[i]!= '\0') { if(cmds[i]!=' ') cmd[cmd_num][j++]=cmds[i]; else { if ((cmds[i+1]!='\0')&&(cmds[i+1]!=' ')) cmd_num++; j = 0; } i++; } cmd_num++; }
gets()函数得到输入的字符串 以’\n’结束
接下来实现比较复杂的解释输入的“指令”的函数,以下是包含了管道的实现的代码,可能比较繁冗,读者看思路即可:
函数思路:
当还有命令词未判断时循环:判断是否为第一个参数->判断是否包含管道->执行相应的命令(内部和外部,其中外部命令是指在unix操作系统下以文件的形式存在的命令函数,故可用fork-execve-wait-exit模型来调用,切记要让子进程exit)
int CommandTransform(){ int fd[10][2]; int pip = -1; int i = 0; pid_t pid; if (strlen(cmd[0])!=0) while(i<cmd_num) { if (strcmp(cmd[i],"cd") == 0) { if (i==0) { int fp; if (strlen(cmd[1])==0) return 0; //cd command can't use the pipe '|' if(strlen(cmd[2])!=0) return 1; const char* p = cmd[1]; if((fp=open(p,O_RDONLY)) < 0) //find the path { printf("Can not open the directory %s\n",cmd[1]); return 0; } if (fchdir(fp) < 0) //call fchdir() to change dir { printf("cd failed,try again\n"); return 0; } return 0; } else { close(0); dup2(fd[pip][0],0);; close(fd[pip][1]); read(fd[pip][0],cmd[i+1],40); dup2(0,fd[pip][0]); const char* p = cmd[i+1]; int fp; if((fp=open(p,O_RDONLY)) < 0) //find the path { printf("Can not open the directory %s\n",p); return 0; } if (fchdir(fp) < 0) //call fchdir() to change dir { printf("cd failed,try again\n"); return 0; } return 0; } } else if (strcmp(cmd[i],"echo") == 0) { if (i==0) { if (strlen(cmd[2])==0) { printf("%s\n",cmd[i+1]); return 0; } else if (strcmp(cmd[2],"|")==0) { if(pipe(fd[++pip])<0) { printf("pipe error!/n"); return 0; } if((pid = fork())<0) { printf("fork error!/n"); return 0; } else if(pid == 0) { close(1); dup2(fd[pip][1],1); close(fd[pip][0]); write(fd[pip][1],cmd[1],40); exit(0); } else if (pid >0) { waitpid(pid,NULL,0); i+=3; } } else return 1; } else { if(strlen(cmd[i+1])==0) { close(0); dup2(fd[pip][0],0); close(fd[pip][1]); read(fd[pip][0],cmd[i+1],40); dup2(0,fd[pip][0]); printf("%s\n",cmd[i+1]); return 0; } else if (cmd[i+1]!="|") { printf("input --error!\n"); return 0; } else { close(0); fd[pip][0]=dup(0); close(fd[pip][1]); read(fd[pip][0],cmd[i+1],40); if(pipe(fd[++pip])<0) { printf("pipe error!/n"); return 0; } close(1); fd[pip][1] = dup(1); close(fd[pip][0]); write(fd[pip][1],cmd[i+1],40); i += 2; } } } else if (strcmp(cmd[i],"wc") == 0) { if (i==0) { FILE *fp; int c; int res_current[3]={0}; const char* p = cmd[1]; if((fp=fopen(p,"r"))==(FILE*)NULL) { c=3; //"wc " takes 3 room while(cmds[c]!='\0') { int flag; res_current[2]++; if(c=='\n') { res_current[0]++; } c++; } printf("line: %d word: %d character: %d\n",res_current[0],cmd_num-1,res_current[2]); return 0; } c=fgetc(fp); //file-get-char function while(c!=EOF) { int flag; res_current[2]++; if(c=='\n') { res_current[0]++; } if(c=='\t' || c== ' ' || c=='\n') { if(flag==0) { res_current[1]++; flag=1; } } else flag=0; c=fgetc(fp); } fclose(fp); printf("line: %d word: %d character: %d in '%s'\n",res_current[0],res_current[1],res_current[2],p); return 0; } else { if((pid = fork())<0) { printf("fork error!/n"); return 0; } if(pid == 0) { FILE * fp; close(0); dup2(fd[pip][0],0); close(fd[pip][1]); read(fd[pip][0],cmd[i+1],40); dup2(0,fd[pip][0]); int res_current[3]={0}; if (strlen(cmd[i+1])==0) { printf("open error!\n"); return 0; } if((fp=fopen(cmd[i+1],"r"))==(FILE*)NULL) { int c=0; while(cmd[i+1][c]!='\0') { int flag; res_current[2]++; if(c=='\n') { res_current[0]++; } if(c=='\t' || c== ' ' || c=='\n') { res_current[1]++; } c++; } printf("line: %d word: %d character: %d\n",res_current[0]+1,res_current[1]+1,res_current[2]); exit(0); } else { int c=fgetc(fp); //file-get-char function while(c!=EOF) { int flag; res_current[2]++; if(c=='\n') { res_current[0]++; } if(c=='\t' || c== ' ' || c=='\n') { res_current[1]++; } c=fgetc(fp); } fclose(fp); printf("line: %d word: %d character: %d in '%s'\n",res_current[0],res_current[1],res_current[2],cmd[i+1]); exit(0); } } else if (pid > 0) waitpid(pid,NULL,0); return 0; } } else if (strcmp(cmd[i],"ls") == 0) { if (i==0) { if (strlen(cmd[1])==0) { char *argv[]={"ls","-al",(char*)0}; char *envp[] = {"PATH=/bin",0}; if((pid = fork())==0) { execve("/bin/ls",argv,envp); exit(0); } else if (pid > 0) waitpid(pid,NULL,0); return 0; } else if(cmd[1]=="|") { if(pipe(fd[++pip])<0) { printf("pipe error!/n"); return 0; } char *argv[]={"ls","-al",(char*)0}; char *envp[] = {"PATH=/bin",0}; if((pid = fork())==0) { close(1); dup2(fd[pip][1],1); close(fd[pip][0]); execve("/bin/ls",argv,envp); exit(0); } else if (pid > 0) waitpid(pid,NULL,0); i+=2; } else { if (cmd[2]=="|") { if(pipe(fd[++pip])<0) { printf("pipe error!/n"); return 0; } char *argv[]={"ls","-al",(char*)0}; char *envp[] = {"PATH=/bin",0}; if((pid = fork())==0) { close(1); dup2(fd[pip][1],1); close(fd[pip][0]); if (chdir(cmd[1])==-1) { printf("no such directory.\n"); exit(0); } execve("/bin/ls",argv,envp); exit(0); } else if (pid > 0) waitpid(pid,NULL,0); i+=2; } else if(strlen(cmd[2])==0) { char *argv[]={"ls","-al",(char*)0}; char *envp[] = {"PATH=/bin",0}; if((pid = fork())==0) { if (chdir(cmd[1])==-1) { printf("no such directory.\n"); exit(0); } execve("/bin/ls",argv,envp); exit(0); } else if (pid > 0) waitpid(pid,NULL,0); return 0; } else return 1; } } else // ls i!=0 { if(strlen(cmd[i+1])==0) { char *argv[]={"ls","-al",(char*)0}; char *envp[] = {"PATH=/bin",0}; close(0); dup2(fd[pip][0],0); close(fd[pip][1]); read(fd[pip][0],cmd[i+1],40); dup2(0,fd[pip][0]); if (strlen(cmd[i+1])==0) { printf("error: ls needs a dir input.\n"); return 1; } if((pid = fork())==0) { if (chdir(cmd[i+1])==-1) { printf("no such directory.\n"); exit(0); } execve("/bin/ls",argv,envp); exit(0); } else if (pid > 0) waitpid(pid,NULL,0); return 0; } else if (cmd[i+1]=="|") { char *argv[]={"ls","-al",(char*)0}; char *envp[] = {"PATH=/bin",0}; close(0); dup2(fd[pip][0],0); close(fd[pip][1]); read(fd[pip][0],cmd[i+1],40); if(pipe(fd[++pip])<0) { printf("pipe error!/n"); return 0; } if((pid = fork())==0) { close(1); dup2(fd[pip][1],1); close(fd[pip][0]); if (strlen(cmd[i+1])!=0&&chdir(cmd[i+1])==-1) { printf("no such directory.\n"); exit(0); } execve("/bin/ls",argv,envp); exit(0); } else if (pid>0) waitpid(pid,NULL,0); i+=2; } else return 1; } }else return 1; }}
最后一个清零函数主要来将字符串清零,以避免对下次输入造成影响。
void Clear(){ int i=0; memset(cmds, 0, sizeof(char *)); //clear cmds while (i < cmd_num) memset(cmd[i++], 0, sizeof(char *)); //clear cmd[i] memset(cmd, 0, sizeof(char **)); //clear cmd }
其中涉及到的头文件如下:
#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <pwd.h>#include <fcntl.h>#include <string.h>#include <unistd.h>
运行截图:
至此,一个简单的shell命令解释器就完成了,有几个涉及到管道的蛋疼的功能还是有点烂尾,读者可在此基础上修改。
0 0
- 自编shell命令解释器
- 自编简单的shell命令解释器要求及代码
- shell命令解释器心得
- Shell命令解释器要求
- shell命令语言解释器
- 自准备写shell解释器以来
- Shell命令解释器项目规划
- bash命令解释器(shell)
- shell简介:shell是一个命令解释器
- shell: ar命令选项解释
- 编写简单的网络版shell命令解释器
- C++基础课 —>命令解释器(SHELL)的用法
- 写一个简单的shell命令解释器
- Shell解释器DIY
- shell 解释器切换
- 用shell解释Symfoware的rdbddlex命令
- 使用有限状态机(FSM)解释shell 命令
- 简述:shell 解释命令,调用程序
- 为docker容器分配固定IP
- Flowerbed can place flowers problem
- 关于PF_RING/Intel 82599/透明VPN的一些事
- 启动数据库报错:ORA-27123: unable to attach to shared memory segment
- Android 底部TabActivity(3)——ActivityGroup|顶部底部均有Tab标签之二
- 自编shell命令解释器
- C++ 关键字 explicit
- SPI-Service Provider Interface
- Architectures 和 Valid Architectures
- 德国人要懒得逆天了 盘点家居省力小物
- 连续执行 Shell 命令
- yii 公共页面部分
- mybatis 传递多参数(不使用实体)
- IOS-NSNotification的简单使用流程: