Linux内核编程实验二
来源:互联网 发布:金蝶在线软件 编辑:程序博客网 时间:2024/05/21 10:08
1、实验名称:shell命令解释系统设计实验
2、实验要求:
问题 A:
实现一个能处理前后台运行命令的 shell。
问题 B:
实现一个带有管道功能的 shell。
问题 C:
实现一个能处理 I/O 重定向的 shell。
问题 D:
实现一个能在一行上处理多条命令的 shell。
将问题 A-D 集中到一个 shell 解析程序中。
3、解决思路
第一步解决问题D。一行上多条命令使用 ; 分开,;两边可以有空格,也可以没有,或者都考虑(健壮性),本方案采用没空格。根据 ; 将其拆分成多条命令,逐条执行即可。
第二步解决问题A。让进程在后台运行,意味着父进程不需要等待子进程运行完毕。否则使用waitpid()函数让父进程等待一下即可。
第三步解决输出重定向,即问题C。根据定向符 > 获得后面的文件名。使用open()打开,使用dup2()函数将标准输出重定向到该文件。那么该进程的输出都将添加到文件中,而不是终端。通常在子进程内进行相应操作。
第四步解决输出重定向,问题C。根据输入定向符 < 获得后面文件名。使用open打开。使用dup2将标准输入重定向到该文件,那么该进程将使用该文件作为输入,而不是终端。
第五步解决管道问题。此处使用匿名管道。匿名管道使用pipe(fds)创建。fds为int类型长度为2的数组。fds[0]为读取数据端。fds[1]为写入数据端。创建两个进程一个管道。进程1关闭读端,将标准输出重定向到管道写端,将数据暂时保存在管道内。进程2关闭写端,将标准输入重定向到管道读端,将管道内数据读出,完成进程通信。
不足之处,仅供参考:
缺点一是支持格式有限。比如
普通命令:ls -a /bin //加粗部分必须为全路径
输出重定向:ls /bin > /home/me/shiyan/test.c //>两侧必须空格
输入重定向:cat < /home/me/shiyan/test.c
管道:cat /home/me/shiyan/test.c | sort //管道两端命令不支持出现重定向
//管道符号两侧必须有空格
后台运行:ls /bin > /home/me/shiyan/test.c& //&符号必须紧跟着
多条命令:ls /home;ls /bin //多条命令分号两边无空格
所有测试命令必须严格遵循上面的格式,否则将可能导致错误的运行结果。
另外一个缺点是,没有完整测试所有linux命令,只测试了部分简单常用命令,因此可能部分命令不支持。
4、实现代码
#include <stdio.h>#include <string.h> //strlen()#include <unistd.h> //fork()#include <sys/types.h> //pid_t#include <sys/wait.h> //waitpid()#include <stdlib.h> //exit()#include <fcntl.h> //open()#define MAXLEN 80#define MAXPARA 8int checkpipe(char *command,int comlen)//判断是否包含|{ int i; for(i=0; i<comlen; i++) { if(command[i] == '|') return i; } return -1;}int checkout(char *command,int comlen)//判断是否包含>{ int i; for(i=0; i<comlen; i++) { if(command[i] == '>') return 1; } return 0;}int checkin(char *command,int comlen) //判断是否包含<{ int i; for(i=0; i<comlen; i++) { if(command[i] == '<') return 1; } return 0;}void runcommand(char *command){ int comlen = strlen(command); int backrun = 0; char *argv1[MAXPARA],*argv2[MAXPARA]; int index1,index2; int i,fd,pipei,fds[2]; char *filename; pid_t p1,p2; if(command[comlen-1] == '&')//是否后台运行 { backrun = 1; command[comlen-1] = 0; comlen--; } pipei = checkpipe(command,comlen); if(pipei > -1)//有管道 { command[pipei-1] = 0; command[pipei] = 0; command[pipei+1] = 0; index1 = 0; argv1[index1++] = command; for(i=0; i<pipei-1; i++) { if(command[i] == ' ') { command[i] = 0; argv1[index1++] = &command[i+1]; } } argv1[index1] = NULL; i = pipei + 2; index2 = 0; argv2[index2++] = &command[i]; for(; i<comlen; i++) { if(command[i] == ' ') { command[i] = 0; argv2[index2++] = &command[i+1]; } } argv2[index2] = NULL; //命令处理完毕,建立管道,进程 pipe(fds); p1 = fork(); if(p1 == 0) { close(fds[0]);//关闭读端 close(STDOUT_FILENO); dup2(fds[1],STDOUT_FILENO);//重定向 close(fds[1]); execvp(argv1[0],argv1);//该函数执行后进程结束 } else { if(backrun == 0) waitpid(p1,NULL,0); p2 = fork(); if(p2 == 0) { close(fds[1]); close(STDIN_FILENO); dup2(fds[0],STDIN_FILENO); close(fds[0]); execvp(argv2[0],argv2); } else { //父进程关闭管道,让两个子进程进行通信 close(fds[0]); close(fds[1]); waitpid(p2,NULL,0); } } } else { if(checkout(command,comlen) == 1)//输出重定向 { index1 = 0; argv1[index1++] = command; for(i=0; i<comlen; i++) { if(command[i] == ' ') { command[i] = 0; if(command[i+1] == '>') break; argv1[index1++] = &command[i+1]; } } argv1[index1] = NULL; i = i + 3; filename = &command[i]; p1 = fork(); if(p1 == 0) { fd = open(filename,O_WRONLY); close(STDOUT_FILENO); dup2(fd,STDOUT_FILENO); close(fd); execvp(argv1[0],argv1); } else { if(backrun == 0) { waitpid(p1,NULL,0); } } } else if(checkin(command,comlen) == 1)//输入重定向 { index1 = 0; argv1[index1++] = command; for(i=0; i<comlen; i++) { if(command[i] == ' ') { command[i] = 0; if(command[i+1] == '<') break; argv1[index1++] = &command[i+1]; } } argv1[index1] = NULL; i = i + 3; filename = &command[i]; p1 = fork(); if(p1 == 0) { fd = open(filename,O_RDONLY); close(STDIN_FILENO); dup2(fd,STDIN_FILENO); close(fd); execvp(argv1[0],argv1); } else { if(backrun == 0) { waitpid(p1,NULL,0); } } } else//普通命令 { index1 = 0; argv1[index1++] = command; for(i=0; i<comlen; i++) { if(command[i] == ' ') { command[i] = 0; argv1[index1++] = &command[i+1]; } } argv1[index1] = NULL; p1 = fork(); if(p1 == 0) { execvp(argv1[0],argv1); } else { if(backrun == 0) { waitpid(p1,NULL,0); } } } }}int main(){ char linebuf[MAXLEN], *command; int buflen,i; while(1) { write(STDOUT_FILENO,"$",1); fgets(linebuf,MAXLEN,stdin); buflen = strlen(linebuf); if(linebuf[buflen-1] == '\n') { linebuf[buflen-1] = 0; buflen--; } if(strcmp(linebuf,"exit") == 0) exit(0); else { command = linebuf; for(i=0; i<buflen; i++) { if(linebuf[i] == ';') { linebuf[i] = 0; runcommand(command); //循环执行多条命令 command = &linebuf[i+1]; } } runcommand(command); //多条命令最后一条 } } return 0;}
5、程序的健壮性优化请参阅:
http://www.powerxing.com/unix-simple-shell-with-argv/
- Linux内核编程实验二
- Linux内核分析:实验二
- Linux内核分析实验二
- Linux内核分析:实验二
- Linux内核分析:实验二
- linux内核编程实验一
- linux内核编程实验三
- linux内核编程(二)
- Linux内核|实验六 内核模块编程
- Linux实验二:Linux 内核模块测试
- linux内核实验二实现过程
- “Linux内核分析”实验报告二
- Linux内核|实验一 Shell编程
- Linux 内核模块编程二
- Linux内核编程二:内核模块
- 主题:《Linux内核模块编程指南》(二)
- 《Linux内核编程指南》心得之二
- Linux 内核编程之文件系统(二)
- Qt 添加资源文件
- Flink on Hadoop 从零搭建
- POJ 3233 Matrix Power Series(矩阵快速幂)
- hdu 1878 欧拉回路
- nodejs 里面执行 es6 的语法语句
- Linux内核编程实验二
- 第七周项目3-用多个文件组织多个类的程序
- 从无到有:软件项目过程敏捷实践
- java.lang.NoClassDefFoundError;java.io.IOException: Cannot initialize Cluster.
- python语法基础归纳(3)--函数
- Android API Guides---Supporting Tablets and Handsets
- sqlite线程模式
- SpringMVC中文乱码总结
- [bzoj4542][HNOI2016]大数