shell命令解释器实验报告
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验报告实验名称:实现一个shell命令解释器
学员:
学号:
年级:
专业:所属学院:计算机学院指导教员:职称:
实验室:实验日期:
目录
1.功能描述 (3)
2.主要数据结构 (3)
3.主要程序流程图 (4)
4.主要功能实现方法和系统调用 (4)
4.1初始化环境 (4)
4.2打印提示符,获取用户输入 (5)
4.3解析命令 (5)
4.4执行命令 (5)
4.4.1内部命令 (5)
4.4.2外部命令 (5)
4.4.3重定向功能 (6)
4.4.4管道功能 (6)
5.测试结果 (7)
6.心得体会 (10)
1.功能描述
本实验完成了一个shell命令解释器,实现了shell的解释命令功能,实现了内部命令(包括自定义命令)、外部命令、重定向功能和多管道等功能。具体功能描述如下:
1)内部命令:
●可以使用常用的如cd、echo、history、exit等命令
●自定义命令
1)smile命令:打印出笑脸
2)myinfo命令:打印出作者信息和版本信息
2)外部命令:可实现cp、rm等所有外部命令。
3)重定向:通过输入重定向符号’<’ 或输出重定向’>’ ,把一行命令分成
两部分,前者为需要执行的命令,后者为一个重定向文件。输入重定向
是把文件内容作为输入传到前面的命令中,而输出重定向则是把命令的
结果传入重定向文件中。
4)管道:通过管道符号’|’ 把一条命令分成两部分,前一部分命令运行后,
将结果放入管道,后一部分命令从管道中取出该结果,作为输入继续执
行。最多可以实现10个管道。
2.主要数据结构
本程序主要使用字符数组进行命令、路径的存储与分析。
3.主要程序流程图
命令的分析执行过程包括:初始化环境,打印提示符,获取用户输入命令,解析命令,寻找命令文件和执行命令,如图1。
图1程序设计流程图
4.主要功能实现方法和系统调用
下面将详细说明本shell解释器的实现原理和所用到的系统调用。
总结起来用到的系统调用主要有:
Open();close();dup();pipe();execv();chdir();getcwd();
如何使用这些系统调用实现shell的各项功能,下面将详细说明。
4.1 初始化环境
用init_environ()函数进行初始化,准备好执行外部命令可能用到的路径。
⏹void init_environ()
程序初始化,打开路径文件os_profile,调用getenviron()函数,将查找路径放入envpath[]中。
⏹void getenviron(char *str)
将路径文件中可能的路径按':'分开,存入envpath[]中。
4.2 打印提示符,获取用户输入
用一个死循环接受用户的输入,直到用户输exit命令。每次打印出当前的工作目录。getcwd(dir,sizeof(dir)),利用getcwd这个系统调用获取当前工作目录的绝对路径。
4.3 解析命令
用一个for循环遍历用户输入input,按照空格’’把各个分词分解开并依次存入arg[ ]数组。Input中碰到’|’,就去执行pipel( )函数,处理管道命令;碰到’<’,就去执行redirect_in(),处理输入重定向命令;碰到’>’,就去执行redirect_out(),处理输出重定向命令。处理完管道和重定向命令后,接着处理自己写的内部命令,最后剩下的就是外部命令。
4.4 执行命令
4.4.1 内部命令
1)cd命令
cd命令的实现利用chdir(arg[1])这个系统调用,将目录改到arg[1]的值。
2)echo命令
将arg[1]打印出来。
3)history命令
用全局变量cmd_num计数,打印出命令序号和相应的用户输入。
4)exit命令
当用户输入exit时,打印出“bye,bye ~~”,并break出程序的主for循环,
退出自己写的shell。
5)自定义命令
1)smile命令
打印出一个笑脸*^_^*,此命令有点娱乐成分。
2)myinfo命令
打印出作者信息author:zhaojingyue 201106021031和版本信息updating time:2013.12.10
4.4.2 外部命令
首先用is_founded( )函数把外部命令的执行文件路径存入buf,接着用fork 系统调用建立一个子进程用于执行该外部命令,然后用execv到buf说存储的路径下执行arg所对应的命令,最后用waitpid向父进程发信号。其中,is_founded( )函数具体实现如下:
int is_founded(char *cmd)
程序初始化时,已经将命令可能存在的路径置于envpath[i]数组中,函数
is_founded 做的工作就是把路径和命令存入buf 数组中,在相应的路径下查找、判断命令是否存在,如果找到返回1,没有则返回0。判断时用到系统调用函数access。
4.4.3 重定向功能
我把重定向分为输入重定向redirect_in()和输出重定向redirect_out()两个函数来处理。
⏹redirect_in()
输入重定向就是把改变命令的输入对象。
先用open这个系统调用以只读方式打开命令中指出的文件,然后用dup将标准输入的文件描述符保存在save_fd中,接着是关键的dup2,用刚刚打开的文件替换掉标准输入,这样就实现了重定向,最后用调用close关闭文件,不让它继续被用。
接下来的操作同外部命令的处理一样,用is_founded(arg[0])函数找到命令执行程序,fork子进程,execv执行此命令,waitpid等待子进程结束发信号给父进程。
执行玩命令之后不要忘了再dup2回来,用一开始保存在save_fd中的文件描述符替换掉现在的标准输入,这样,标准输入就是正常的了。
⏹redirect_out()
输出重定向就是把改变命令的输出对象。
先用open这个系统调用以可写方式打开命令中指出的文件,第二个参数是O_RDWR|O_CREAT|O_APPEND,即若文件不存在就创建一个,然后把要写入的内容拼接在原文件的后面。然后用dup将标准输出的文件描述符保存在save_fd 中,接着是关键的dup2,用刚刚打开的文件替换掉标准输出,这样就实现了重定向,最后用调用close关闭文件,不让它继续被用。
接下来的操作同外部命令的处理一样,用is_founded(arg[0])函数找到命令执行程序,fork子进程,execv执行此命令,waitpid等待子进程结束发信号给父进程。
执行玩命令之后不要忘了再dup2回来,用一开始保存在save_fd中的文件描述符替换掉现在的标准输出,这样,标准输出就是正常的了。
4.4.4 管道功能
管道功能用自定义函数pipel()实现。
⏹pipel()
该函数实现了连续执行多条管道的功能,最多可连续执行10条管道。函数主要执行流程如下:
1)初始化10个管道的读、写端,都置为-1。
2)进行命令解析,把各条命令分解存到argp[][]二维数组中,遇到管道符
号”|”则置为NULL。
3)用系统调用pipe(fd[I])创建li_cmd个管道。
4)接下来进入for循环,一条一条执行命令。每条命令的执行过程如下: