进程实践——myshell
来源:互联网 发布:10月份经济数据2017 编辑:程序博客网 时间:2024/05/10 13:54
要求:
解释执行命令,支持输入输出重定向,支持管道,后台运行程序。
/*************************************************************************> File Name: shell.c> Author:wyf > Mail:Catherine199787@outlook.com > Created Time: 2016年07月30日 星期六 10时54分55秒************************************************************************/#include<stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<sys/wait.h>#include<unistd.h>#include<fcntl.h>#include<stdlib.h>#include<dirent.h>#include<string.h>#include<malloc.h>#define normal 0#define out 1#define in 2#define pipe 3//自定义错误函数void err(char* err_string, int line){ perror(err_string); fprintf(stderr, "line:%d", line); return;}//判断命名的正确性int right(char *arg){ DIR *dir; struct dirent* ptr; char *path[] = {"./","/bin","/usr/bin/",NULL}; //环境变量PATH的路径 int i; if(strncmp(arg, "./", 2) == 0){ //将路径改为当前目录 arg = arg + 2; //指针移到/下一个字节 } for(i = 0; path[i] != NULL; i++){ //查找命令 dir = opendir(path[i]); if(dir == NULL){ err("open_bin error", __LINE__); } while((ptr = readdir(dir)) != NULL){ if(strcmp(ptr->d_name, arg) == 0){ closedir(dir); return 1; } } closedir(dir); } return 0;}//管道的执行函数void argpipe(char *argn[], char *arg[]){ int pid; int status; int fd; pid = fork(); if(pid < 0){ err("pipe_fork", __LINE__); } else if(pid == 0){ if(!right(arg[0])){ err("pipe arg", __LINE__); } fd = open("/tmp/youdonotknowfile", O_WRONLY | O_CREAT | O_TRUNC,0644); dup2(fd, 1); execvp(arg[0], arg); exit(0); } if(waitpid(pid, &status, 0) == -1){ err("pipe_wait", __LINE__); } if(!right(argn[0])){ err("pipe_arg", __LINE__); } fd = open("/tmp/youdonotknowfile", O_RDONLY); dup2(fd, 0); execvp(argn[0], argn); if(remove("/tmp/youdonotknowfile")){ err("remove", __LINE__); }}//输入函数void arginput(char *buf){ int len = 0; gets(buf); len = strlen(buf); if(len >= 255){ err("arginput", __LINE__); }}//解析输入的命令void argexplain(char * buf, char arglist[][255], int *argcount){ int number = 0; int i = 0; while(1){ if(buf[i] == '\0'){ break; } else if(buf[i] != ' '){ arglist[*argcount][number] = buf[i]; number++; } else{ arglist[*argcount][number] = '\0'; number = 0; *argcount = *argcount + 1; //*argcount 为下标 } i++; }}//执行输入void argdo(int argcount, char arglist[][255]){ char *arg[argcount+1]; int wrong = 0; int how = 0; int background = 0; int fd; int i; int status; char path[100]; //各种无法清空path的缓存,有八阿哥。 char *argn[argcount+1]; pid_t pid; for(i = 0; i <= argcount ; i++){ //准备execvp的第二个参数 arg[i] = arglist[i]; } arg[i] = NULL; for(i = 0; i <= argcount; i++){ if(strcmp(arg[i], "&") == 0){ if(i == (argcount - 1)){ background = 1; arg[argcount-1] = NULL; break; } else{ err("too many '&'", __LINE__); return; } } } for(i = 0; arg[i] != NULL; i++){ if(strcmp(arg[i], ">") == 0){ wrong++; how = out; if(arg[i+1] == NULL){ wrong++; } } else if(strcmp(arg[i], "<") == 0){ wrong++; how = in; if(arg[i+1] == NULL){ wrong++; } } else if(strcmp(arg[i], "|") == 0){ wrong++; how = pipe; if(arg[i+1] == NULL){ wrong++; } else if(i == 0){ wrong++; } } } if(wrong > 1){ err("too many arg", __LINE__); } pid = fork(); if(pid < 0){ err("fork error", __LINE__); } switch(how){ case 0:{ if(pid == 0){ if( !right(arg[0]) ){ // perror("wrong arg"); exit(0); } execvp(arg[0], arg); exit(0); } } break; case 1:{ for(i = 0; arg[i] != NULL; i++){ if(strcmp(arg[i], ">") == 0){ strcpy(path, arg[i+1]); arg[i] = NULL; } } if(pid == 0){ if( !right(arg[0]) ){ err("wrong arg", __LINE__); } printf("%s\n",path); fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644); if(fd < 0){ err("open faild", __LINE__); } dup2(fd, 1); //通过dup2实现标准输出 execvp(arg[0], arg); } } break; case 2:{ for(i = 0; arg[i] != NULL; i++){ if(strcmp(arg[i], "<") == 0){ strcpy(path, arg[i+1]); arg[i] = NULL; } } if(pid == 0){ if( !right(arg[0]) ){ err("wrong arg", __LINE__); } fd = open(path, O_RDONLY); if(fd < 0){ err("open faild", __LINE__); } dup2(fd, 0); execvp(arg[0], arg); exit(0); } } break;case 3:{ for(i = 0; arg[i] != NULL; i++){ if(strcmp(arg[i], "|") == 0){ arg[i] = NULL; int j; for(j = i+1; arg[j] != NULL; j++){ //管道命令数组 argn[j-i-1] = arg[j]; } argn[j-1-i] = NULL; break; } } if(pid == 0){ argpipe(argn, arg); }}break; default: break; }//switch if(background == 1){ //后台运行父进程不管子进程直接返回 return ; } if(waitpid(pid, &status, 0) == -1){ //他爸等他娃结束 err("wait for chil error", __LINE__); } }/******************主函数***********************/int main(int argc,char *argv[]){ char *buf; int argcount = 0, i; char arglist[100][255]; char **arg = NULL; buf = (char *)malloc(255); if(buf == NULL){ err("malloc", __LINE__); } while(1){ memset(buf, 0 ,256); printf("my_shell$$"); arginput(buf); if(strcmp(buf, "exit") == 0 || strcmp(buf, "logout") == 0) { break; } for(i = 0; i < 100; i++){ arglist[i][0] = '\0'; } argcount = 0; argexplain(buf, arglist, &argcount); argdo(argcount, arglist); } if(buf != NULL){ free(buf); buf = NULL; } return 0;}
总结:
参考了课本,对于重定向,管道的概念不是很清晰,程序的布局把握的不好,二级指针的运用不是很熟练。
问题:
很多。
0 0
- 进程实践——myshell
- myshell
- Perl多进程实践——fork
- myshell.c
- 操作系统实践(9)——进程、多进程、系统调用、进程调度
- Myshell解析器
- 简单myshell的实现
- 实现自己的myshell
- 自己的myshell
- 实现自己的myshell
- 模拟实现myshell
- 实现自己的myshell
- eCos Synthetic实践(三)——I/O辅助进程
- Linux企业级项目实践之网络爬虫(6)——将程序设计成为守护进程
- 实践杂谈(1)—— Bash脚本实现并行化和进程数控制
- .NET跨平台实践:再谈用C#开发Linux守护进程 — 完整篇
- 进程管理-实践篇
- 多进程最佳实践
- IDA经典教程
- Grpc的一个简单的负载均衡类库
- 修改Struts2的struts.xml配置文件位置和名称-重点是init-param参数用来切换加载的路径
- Struts 2 常用标签(Tag)详解
- Android--微信支付的坑
- 进程实践——myshell
- Spring MVC 简介
- 嵌入式技能点
- spring mvc 下载文件,ie不支持解决
- Java substring lastIndex
- pyqt实现界面化编程
- 符号表
- Music app框架设计及总结
- spring容器归纳(二)