shell命令解释器实验报告.docx
- 文档编号:30107940
- 上传时间:2023-08-05
- 格式:DOCX
- 页数:12
- 大小:722.11KB
shell命令解释器实验报告.docx
《shell命令解释器实验报告.docx》由会员分享,可在线阅读,更多相关《shell命令解释器实验报告.docx(12页珍藏版)》请在冰豆网上搜索。
shell命令解释器实验报告
实验报告
实验名称:
实现一个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.主要数据结构
本程序主要使用字符数组进行命令、路径的存储与分析。
程序中用到的一些关键的数据变量如下表所示:
名称
类型
功能
input[200]
char
存放用户输入
arg[256]
char*
命令解析部分,将用户输入的命令按’’分开后,依次存入该数组中
arg_num
int
指明了命令分词的个数
cmd[300]
char*
存放历史命令记录的数组
cmd_num
int
记录运行解释器以来所执行的命令总数
dir
char
存放当前工作目录
argp[20][100]
char*
存放管道命令的命令解析分词的二维数组
fd[100][2]
int
管道描述符,用于存放100个管道的读写两端:
fd[][0]为读管道;fd[][1]为写管道
li_cmd
Int
存放管道个数
envpath[200]
char*
存放可能的外部命令执行文件路径
3.主要程序流程图
命令的分析执行过程包括:
初始化环境,打印提示符,获取用户输入命令,解析命令,寻找命令文件和执行命令,如图1。
图1程序设计流程图
4.主要功能实现方法和系统调用
下面将详细说明本shell解释器的实现原理和所用到的系统调用。
总结起来用到的系统调用主要有:
Open();close();dup();pipe();execv();chdir();getcwd();
如何使用这些系统调用实现shell的各项功能,下面将详细说明。
4.1初始化环境
用init_environ()函数进行初始化,准备好执行外部命令可能用到的路径。
⏹voidinit_environ()
程序初始化,打开路径文件os_profile,调用getenviron()函数,将查找路径放入envpath[]中。
⏹voidgetenviron(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:
zhaojingyue201106021031和版本信息updatingtime:
2013.12.10
4.4.2外部命令
首先用is_founded()函数把外部命令的执行文件路径存入buf,接着用fork系统调用建立一个子进程用于执行该外部命令,然后用execv到buf说存储的路径下执行arg所对应的命令,最后用waitpid向父进程发信号。
其中,is_founded()函数具体实现如下:
⏹intis_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循环,一条一条执行命令。
每条命令的执行过程如下:
a)调用is_founded(argp[i][0])函数找到命令执行文件。
b)把命令的读端赋给pipe_in(第一条命令除外),把命令的写端赋给pipe_out(最后一条命令除外)。
c)用fork调用子进程执行命令。
d)调用dup2用命令的读端pipe_in代替标准输入然后关闭pipe_in,用命令的写端pipe_out代替标准输出然后关闭pipe_out。
对于第一条命令无需改变读端,对于最后一条命令无需改变写端。
e)设置好读写端后,调用execv执行命令。
5.测试结果
✧内部命令测试:
分别输入echo、myinfo、smile、history、cd、exit命令,并查看结果。
✧外部命令测试:
分别输入ls、wc、man命令,并查看结果。
man命令的详细结果:
✧重定向命令测试:
先ls看一下当前目录的内容,将ls命令的结果输出到重定向文件zhao中,再用ls命令检查是否新建了zhao文件。
然后用cat命令查看zhao文件的结果,最后把zhao作为wc命令的输入,并查看结果。
✧管道命令测试:
测试1个、2个和3个管道。
6.心得体会
罗老师一直很强调能力的培养,非常重视这个实验。
他说我们听课、考试,锻炼的只是我们的记性,考完试就都还给老师了。
虽然我不是十分认同这个观点,但我觉得这种说法是有一点道理的。
因为无论是上学期学习的计算机原理还是这学期开设的操作系统、计算机网络、数据链等等课程,只是课堂听老师讲解、传授知识,即使理解透彻了,也还是十分抽象,落实不到真正的技术实现上,解决不了实际问题。
要真正理解掌握,真正有所体会,还是得靠自己动手,从这学期的cpu实验、网络实验也可以看出实践的重要性。
“自己动手实践过的,一辈子都忘不了。
”这是罗老师、蔡老师等原话,我深以为然也。
以前常常自嘲说:
“deadline是第一生产力”。
一直很难克服自己的拖延症,这次的实验也不例外。
刚开始的时候虽然课程也比较紧张,但还是有一些时间的,但因为贪玩、畏难迟迟没有开始。
到后来各种大实验一来,就更加觉得时间不够用了。
人总是要逼一逼自己的,或许这样才能出成果。
于是硬着头皮开始了shell命令解释器的实验。
一开始的时候,是先从熟悉Linux系统开始的,用惯了图形化的Windows,我甚至连终端是什么,在哪里打开都不知道。
更不理解我要做的到底是个什么东西,什么是命令解释器,我最后要呈现出一个什么样的效果才算完成。
然后就对照着《实验指导书》,从熟悉Linux的操作和各种命令开始,到学会gcc编译,再到着手编写shell命令解释器。
一步一步,走得艰难但印象深刻,缓慢而脚踏实地。
编写shell命令解释器的过程中,让我体会最深的两点,一是程序设计的框架,二是各种系统调用的使用。
开始的时候,跟着实验指导书做,但发现指导书上的是一些程序片段,程序的框架结构,要自己先构思好,不然编起来会思路不清。
我也是程序写到后来才渐渐意识到框架问题的,哪些单独做成一个函数放在main的外面,哪些直接在main里面写,各个模块、函数之间的逻辑结构又是怎样的,这个很重要。
尤其对于这种,for里套for的程序结构,更有搞清楚,不然很容易陷进去出不来。
为了实现一些命令,要使用各种系统调用。
让我印象最深的是fork、dup2和open。
Fork子程序调用让我第一次在编程中体会到程序的并行执行,尤其是周鹏上课时问老师的那个问题,哪些是父进程执行,哪些是子进程执行,哪些都会执行,简直太有趣了。
用dup2是为了做重定向和管道,其中重定向还要注意在dup2之前先dup一个,保存一下,结束之后在dup2回来。
当然还有用来打开文件的open,由于open的参数的可能情况太多,涉及到各种权限,每次都要去查一下,还是没有完全记住。
在这个实验过程中,我锻炼了自我学习的能力,当然还学会了及时与同学交流,向老师请教。
我认识到能力的增长是一个循序渐进,但又可以是一个突飞猛进的过程,有时候就是卡在某一个结点,等一段时间想通了就会有很大收获。
最后感谢罗老师和教辅的悉心指导,感谢毫不保留地交流的同学们,当然还要感谢攻克难关、坚持做下来的自己。
未来,我会继续努力的!
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- shell 命令 解释 实验 报告