shell命令解释器实验报告.doc_第1页
shell命令解释器实验报告.doc_第2页
shell命令解释器实验报告.doc_第3页
shell命令解释器实验报告.doc_第4页
shell命令解释器实验报告.doc_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

shell 命令解释器 第 1 页/共 10 页 实实 验验 报报 告告 实验名称: 实现一个 shell 命令解释器 学 员: 学 号: 年 级: 专 业: 所属学院: 计算机学院 指导教员: 职 称: 实 验 室: 实验日期: shell 命令解释器 第 2 页/共 10 页 目录目录 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 shell 命令解释器 第 3 页/共 10 页 1. 功能描述功能描述 本实验完成了一个 shell 命令解释器,实现了 shell 的解释命令功能,实现 了内部命令(包括自定义命令) 、外部命令、重定向功能和多管道等功能。具体 功能描述如下: 1)内部命令: 可以使用常用的如 cd、echo、history、exit 等命令 自定义命令 1)smile命令:打印出笑脸 2)myinfo命令:打印出作者信息和版本信息 2)外部命令:可实现 cp、rm 等所有外部命令。 3)重定向:通过输入重定向符号 ,把一行命令分成 两部分,前者为需要执行的命令,后者为一个重定向文件。输入重定向 是把文件内容作为输入传到前面的命令中,而输出重定向则是把命令的 结果传入重定向文件中。 4)管道:通过管道符号 | 把一条命令分成两部分,前一部分命令运行后, 将结果放入管道,后一部分命令从管道中取出该结果,作为输入继续执 行。最多可以实现 10 个管道。 2. 主要数据结构主要数据结构 本程序主要使用字符数组进行命令、路径的存储与分析。 程序中用到的一些关键的数据变量如下表所示: 名称类型功能 input200char存放用户输入 arg256char* 命令解析部分,将用户输入的命令按 分开 后,依次存入该数组中 arg_numint指明了命令分词的个数 cmd300char*存放历史命令记录的数组 cmd_numint记录运行解释器以来所执行的命令总数 dirchar存放当前工作目录 argp20100char *存放管道命令的命令解析分词的二维数组 fd1002int 管道描述符,用于存放 100 个管道的读写 两端:fd 0为读管道;fd 1为写管道 li_cmdInt存放管道个数 envpath200char*存放可能的外部命令执行文件路径 shell 命令解释器 第 4 页/共 10 页 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中。 shell 命令解释器 第 5 页/共 10 页 4.2 打印提示符,获取用户输入打印提示符,获取用户输入 用一个死循环接受用户的输入,直到用户输 exit 命令。每次打印出当前的 工作目录。getcwd(dir,sizeof(dir),利用 getcwd 这个系统调用获取当前工作目录 的绝对路径。 4.3 解析命令解析命令 用一个 for 循环遍历用户输入 input,按照空格 把各个分词分解开并依次存入 arg 数 组。Input 中碰到|,就去执行 pipel( )函数,处理管道命令;碰到,就去执行 redirect_out(),处理输出重定向命令。处理完管道 和重定向命令后,接着处理自己写的内部命令,最后剩下的就是外部命令。 4.4 执行命令执行命令 4.4.1 内部命令内部命令 1)cd 命令命令 cd 命令的实现利用 chdir(arg1)这个系统调用,将目录改到 arg1的值。 2)echo 命令命令 将 arg1打印出来。 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) shell 命令解释器 第 6 页/共 10 页 程序初始化时,已经将命令可能存在的路径置于 envpathi数组中,函数 is_founded 做的工作就是把路径和命令存入 buf 数组中,在相应的路径下查找、 判断命令是否存在,如果找到返回 1,没有则返回 0。判断时用到系统调用函数 access。 4.4.3 重定向功能重定向功能 我把重定向分为输入重定向 redirect_in()和输出重定向 redirect_out()两个函 数来处理。 redirect_in() 输入重定向就是把改变命令的输入对象。 先用 open 这个系统调用以只读方式打开命令中指出的文件,然后用 dup 将 标准输入的文件描述符保存在 save_fd 中,接着是关键的 dup2,用刚刚打开的 文件替换掉标准输入,这样就实现了重定向,最后用调用 close 关闭文件,不让 它继续被用。 接下来的操作同外部命令的处理一样,用 is_founded(arg0)函数找到命令 执行程序,fork 子进程,execv 执行此命令,waitpid 等待子进程结束发信号给 父进程。 执行玩命令之后不要忘了再 dup2 回来,用一开始保存在 save_fd 中的文件 描述符替换掉现在的标准输入,这样,标准输入就是正常的了。 redirect_out() 输出重定向就是把改变命令的输出对象。 先用 open 这个系统调用以可写方式打开命令中指出的文件,第二个参数 是 O_RDWR|O_CREAT|O_APPEND,即若文件不存在就创建一个,然后把要写 入的内容拼接在原文件的后面。然后用 dup 将标准输出的文件描述符保存在 save_fd 中,接着是关键的 dup2,用刚刚打开的文件替换掉标准输出,这样就 实现了重定向,最后用调用 close 关闭文件,不让它继续被用。 接下来的操作同外部命令的处理一样,用 is_founded(arg0)函数找到命令 执行程序,fork 子进程,execv 执行此命令,waitpid 等待子进程结束发信号给 父进程。 执行玩命令之后不要忘了再 dup2 回来,用一开始保存在 save_fd 中的文件 描述符替换掉现在的标准输出,这样,标准输出就是正常的了。 4.4.4 管道功能管道功能 管道功能用自定义函数 pipel()实现。 pipel() 该函数实现了连续执行多条管道的功能,最多可连续执行 10 条管道。函数 主要执行流程如下: 1) 初始化 10 个管道的读、写端,都置为-1。 2) 进行命令解析,把各条命令分解存到 argp二维数组中,遇到管道符 号”|”则置为 NULL。 3) 用系统调用 pipe(fdI)创建 li_cmd 个管道。 shell 命令解释器 第 7 页/共 10 页 4) 接下来进入 for 循环,一条一条执行命令。每条命令的执行过程如下: a) 调用 is_founded(argpi0)函数找到命令执行文件。 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 命令,并查看结果。 shell 命令解释器 第 8 页/共 10 页 man 命令的详细结果: 重定向命令测试:先 ls 看一下当前目录的内容,将 ls 命令的结果输出 到重定向文件 zhao 中,再用 ls 命令检查是否新建了 zhao 文件。然后 shell 命令解释器 第 9 页/共 10 页 用 cat 命令查看 zhao 文件的结果,最后把 zhao 作为 wc 命令的输入, 并查看结果。 管道命令测试:测试 1 个、2 个和 3 个管道。 shell 命令解释器 第 10 页/共 10 页 6. 心得体会心得体会 罗老师一直很强调能力的培养,非常重视这个实验。他说我们听课、考试, 锻炼的只是我们的记性,考完试就都还给老师了。虽然我不是十分认同这个观 点,但我觉得这种说法是有一点道理的。因为无论是上学期学习的计算机原理 还是这学期开设的操作系统、计算机网络、数据链等等课程,只是课堂听老师 讲解、传授知识,即使理解透彻了,也还是十分抽象,落实不到真正的技术实 现上,解决不了实际问题。要真正理解掌握,真正有所体会,还是得靠自己动 手,从这学期的 cpu 实验、网络实验也可以看出实践的重要性。 “自己动手实践 过的,一辈子都忘不了。 ”这是罗老师、蔡老师等原话,我深以为然也。 以前常常自嘲说:“deadline 是第一生产力” 。一直很难克服自己的拖延症, 这次的实验也不例外。刚开始的时候虽然课程也比较紧张,但还是有一些时间 的,但因为贪玩、畏难迟迟没有开始。到后来各种大实验一来,就更加觉得时 间不够用了。人总是要逼一逼自己的,或许这样才能出成果。于是硬着头皮开 始了 shell 命令解释器的实验。 一开始的时候,是先从熟悉 Linux 系统开始的,用惯了图形化的 Windows,我甚至连终端是什么,在哪里打开都不知道。更不理解我要做的到 底是个什么东西,什么是命令解释器,我最后要呈现出一个什么样的效果才算 完成。然后就对照着实验指导书 ,从熟悉 Linux 的操作和各种命令开始,到 学会 gcc 编译,再到着手编写 shell 命令解释器。一步一步,走得艰难但印象深 刻,缓慢而脚踏实地。 编写 shell 命令解释器的过程中,让我体会最深的两点,一是程序设计的框 架,二是各种系统调用的使用。 开始的时候,跟着实验指导书做,但发现指导书上的是一些程序片段,程 序的框架结构,要自己先构思好,不然编起来会思路不清。我也是程序写到后 来才渐渐意识到框架问题的,哪些单独做成一个函数放在 main 的外面,哪些直 接在 main 里面写,各个模块、函数之间的逻辑结构又是怎样的,这个很重要。 尤其对于这种,for 里套 for 的程序结构,更有搞清楚,不然很容易陷进去出不 来。 为了实现一些命令,要使用各种系统调用。让我印象最深的是 fork、dup2 和 open。Fork 子程序调用让我第一次在编程中体会到程序的并行执行,尤其是 周鹏上课时问老师的那个问题,哪些是父进程执行,哪些是子进程执行,哪些 都会执行,简直太有趣了。用 dup2 是为了做重定向和管道

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论