Shell命令解释器项目规划

【項目要求】
一、 实现功能:
要求实现一个简单的命令解释器,也就是linux中的shell程序,在本程序中我们将其起名为ysh,要求:
1、 能够执行外部程序命令,命令可以带参数;
2、 能够执行fg、bg、cd、history、exit等内部命令;
3、 使用管道和输入输出重定向;
4、 支持前后台作业,提供作业控制功能,包括打印作业的清单,改变当前运行作业的前/后台状态,以及控制作业的挂起、中止与继续运行;
5、 使用Make工具建立工程;
6、 使用调试器gdb来调试程序;
二、 实验现象:
本程序的ysh程序设计不包括对配置文件和命令行参数的支持。要求ysh提供一个命令提示符,如ysh>,表示接受用户输入,每次执行完成后,再打印下一个命令提示符ysh>,当用户没有输入时,ysh需要一直处于等待输入状态,同时在屏幕上显示一些必要的信息。
三、 Ysh解释程序的具体要求:
1、 外部命令和内部命令:
在大多数情况下,用户输入的命令是执行存储在文件系统下中的可执行程序,我们称之为外部命令或外部程序。Ysh应当支持在执行这些程序时可以将输入/输出重新定向到一个文件,并允许若干个程序使用管道串联起来。我们把由管道连接起来的符合命令以及单独使用的命令成为作业。
外部命令的形式是一系列分隔的字符串。第一个字符串可以是可执行程序的名字,其它的是传递给这个外部程序的参数。如果第一个字符串所声名的可执行文件并不存在或者不可执行,则认为这个命令是错误的。
解释器还必须支持一些内部命令,这些命令在ysh内部实现了特定的动作,下面是一些内部命令,如果用户提交了一个内部命令,ysh应按照下面的描述执行相应动作。
 exit:退出ysh。
 jobs:打印当前正在后台执行的作业和挂起的作业信息。输出信息应采用便于用户理解的格式。
 fg  %<int>:把<int>所标识的作业放到前台运行,如果这个作业原来已经停止,那么他继续运行。Shell应当在打印新的命令提示行之前等待前台运行的子进程结束。
   Bg  %<int>:在后台执行<int>标识的已挂起的进程。
2、 命令行:
当用户在提示符后面输入命令时,输入的整行内容叫做“命令行字符串”,ysh应当保存每一条命令行字符串,直到它表示的作业执行结束,其中包括后台作业和被挂起的作业。
3、 前台和后台作业
ysh应当能够执行前台和后台作业。Shell在前台执行结束之前要一直等待。而在开始执行后台作业时要立刻打印出提示符ysh>,让用户输入下一条命令。
前台作业的执行总是优先于一个后台作业,ysh不需要在打印下一个提示符前等待后台作业的完成,无论是否有后台作业的执行,只要完成一个前台作业,便立即输出提示符ysh>;一个后台作业结束时,ysh应当在作业结束后立刻打印出一条提示信息。
4、 特殊键:
又称组合键。通过终端驱动程序,特殊的组合键可以产生信号给ysh,程序应当对这些信号做出适当的响应。
 Ctrl + Z:产生SIGTSTP信号,这个信号不是挂起ysh,而是让shell挂起在前台运行的作业,如果没有任何前台作业,则该特殊键无效。
 Ctrl+C:产生SIGINT信号,这个信号不是中止ysh,而是通过ysh发出信号杀死前台作业中的进程。如果没有任何前台作业,则该特殊键无效。
5、 分析用户输入:
a) 分隔符和特殊字符
分析用户输入的语法分析器应具有下面介绍的功能,它能够检查用户的输入错误。如果用户输入的某些地方出错了,ysh应当给出合理的出错信息。
ysh每次接受用户输入的一行命令,在用户按下回车键(Enter)后开始执行分析动作。空名令不产生任何操作,而只是打印一个新的提示符。
定义空格符为分隔符,ysh应能处理命令行中间和前后出现的重复空格符。
某些字符被称做“元字符”,它们在用户输入的上下文中具有特殊的定义。这些字符包括”&、|、<、>”。Shell假设这些字符不会出现在程序名、参数名、文件名中,他们是ysh的保留字符。
b) 内部命令:
如果命令行字符串符合前面介绍的内部命令的格式,它就当作一个内部命令被解释。如果不是,就要考虑可能是外部程序的执行,或者是错误的。
c) I/O重定向:
一个程序命令后面可能还跟有元字符“<”或“>”,他们是重定向符号,而在重定向符号后面还跟着一个文件名,在”<”的情况下,程序的输入被重定向到一个指定的文件中去。在”>”的情况下,程序的输出被重定向到一个指定的文件中。如果输出文件不存在,需要创建一个输出文件。如果输入文件不存在,则认为出现了错误。
d) 管道和协同程序
在一条命令行中当若干个命令被元字符“|”分开时,这个元字符代表管道符号。在这种情况下,ysh为每一个子命令都创建一个进程,并把它们的输入、输出用管道连接起来。
例如下面这条命令行:
 progA  argA1 argA2  <  infine  |  progB1  > outfile
应生成progA 和progB 两个进程,ProgA的输入来自文件infile,porgA的输出是progB的输入,并且progB的输出文件是outfile。这种命令行可以通过进程间通信中的管道来实现。
含有一个和多个管道的命令会在如下几种情况下产生错误:
 当其任何一个子程序执行出错时。
 除了第一个子程序以外其它子程序的输入被重定向。
 除了最后一个子程序以外的其它子程序的输出被重定向。
由管道连接的多个进程所组成的作业只有当其所有子进程都执行完毕后才算结束。
e) 后台作业
当用户需要在后台执行一个作业时,可以在作业命令的后面加上元字符“&”。用户以该种方式输入的作业命令都必须放在后台执行,同时并不影响用户与终端的交互
四、 步骤建议:
1、  阅读有关fork、exec、wait和exit系统调用的man帮助手册。
2、  编写小程序练习使用这些系统调用。
3、  实现命令行分析器
4、  使用分析器,写一个简单的shell程序,使它能够执行简单的命令。
5、  增加输入输出重定向功能
6、 添加作业控制特征,主要实现对组合键Ctrl+Z、Ctrl+C的响应,还有实现fg和bg命令功能。
7、 增加对管道的支持
8、 实现上面的所有细节并集成
9、 不断测试
10、 写报告
11、 结束
五、 相关基础知识
1、 Shell与内核的关系
  Shell 是用户和linux内核之间的接口程序,如果把linux内核想象成一个球体的中心,shell就是包围内核的外壳,如图 1所示。当从shell或其他程序向linux传递命令时,内核会做出相应的反应。Shell是一个命令语言解释器,它拥有自己内建的shell命令集,shell也能被系统中其他应用程序所调用。用户在提示符ysh>下输入的命令都是由shell先解释后传递给linux核心的。
2、系统调用
 系统调用是一个“函数调用”,它控制状态的改变。系统调用和普通过程的区别在于系统调用的执行会引起特权级的切换,因为被调用的函数处于操作系统的内核当中,是内核的一部分。
  操作系统定义了一个系统调用集合。为了安全起见,调用操作系统内部的函数必须谨慎的控制,这种控制是由硬件通过陷阱向量执行的。只有那些在操作系统启动时填入陷阱向量的地址,才是正当而且有效的系统调用地址。因此系统调用就是一种在受限制的下进入保护核心的“函数调用”。
  因为操作系统负责进程控制和调度, ysh就需要调用操作系统内部的函数来控制它的子进程。这些函数叫系统调用。在linux中,我们可以区分系统调用和用户层次的库函数,因为系统调用函数手册在查询“帮助”手册的第二部分,而库函数在手册的第三部。在linux中可以通过man命令查询“帮助”手册。例如:使用命令man fork会给出数据手册中第二部分与fork 系统调用有关的解释。还有很多其他的系统调用,都可以通过man命令来进行查阅,你会发现man是很有用的查询参考手册的命令。
下面是在项目中会用到的重要的UNIX系统调用。
  pid_t fork(void) :创建一个新的进程,它是原来进程的一个副本。在fork成功返回后,父进程和子进程都要继续执行fork后面的指令。这两个进程通过fork的返回值进行区分,对父进程fork的返回值是子程序的进程号,对子进程的返回值是0。
  int execvp(const char *file, char *const arvg[]):加载一个可执行程序到调用进程的地址空间中,然后执行这个程序。如果成功,它就会覆盖当前运行的进程内容。有若干个类似的exec系统调用
  void exit (int status):退出程序,使调用进程退出,程序结束。它把status作为返回值返回父进程,父进程通过调用wait系统调用来获得返回值。连接器会为每一个程序结尾连接一个exit系统调用。
  int wait(int *stat_loc):如果没有退出的子程序,则返回退出的子进程的状态:如果没有任何子进程在运行,则返回错误。如果当前有子进程正在运行,则函数会一直阻塞直到有一个子进程退出。
  pid_t waitpid(pid_t pid,int*stat_loc,int options):类似于函数wai,但允许用户等待某个进程组的特定程序,并可以设置等待选项,例如WNOHANG。
  int setpgid(pid_t pid , pid_tpgid):把pid进程的进程组ID设置为pgid。
  int dup2(int fildes,int fileds2):把fileds文件描述符复制到fildes2,如果fileds已经打开,则先将其关闭,然后进行复制,使fileds和fileds2指向同一文件。
int pipe(int fileds[2]):创建一个管道,把管道的读和写文件描述符放到数组fildes中。
<script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/buttonLite.js#style=-1&uuid=&pophcol=3&lang=zh"></script> <script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/bshareC0.js"></script>
阅读(1546) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-06-05 23:39:01

求源代码。。。。谢谢~sysbtsb@163.com

chinaunix网友2010-06-05 23:33:29

汗,你贴个要求出来干嘛用。。。。源代码啊?!!!!

评论热议
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Shell程序的具体要求如下: (1)本实验的user-sh程序设计不包括对配置文件和命令行参数的支持。User-sh应提供一个命令提示符,如“user-sh>”,表示等待用户的输入,执行命令输出的必要信息,然后再打印下一个命令提示符。当用户没有输入时,user-sh需要一直处于随时等待输入状态,同时在屏幕上显示一些基本提示信息。 (2)实现以下内部命令。 exit 结束所有的子进程并退出。 jobs 打印当前正在后台执行的作业和被挂起的作业信息。输出信息应采用便于用户理解的格式。jobs自身是一条内部命令,所以不需要先是在输出上。 history 列出用户最近输入过的N条命令,不论这个命令是否正确执行过。 fg%<pid> 把<pid>所标识的作业放到前台运行。若这个作业原来已经挂起则让其继续运行。 bg%<pid> 把<pid>所标识的已挂起的进程放在后台运行。 (3)进行前台和后台作业切换 user-sh应当在打印新的命令提示符之前等待前台运行的子程序结束。前台作业和后台作业的区别是:shell在前台作业执行完之前要一直处于等待状态。而在开始执行后台作业时要立刻打印出提示符,让用户继续输入下一条命令。 执行前台作业即在提示符后输入一个可执行文件的路径(绝对路径)即可,执行后台作业则需在可执行文件路径后加上一个“&”符号。 前台作业的执行总是优先于一个后台作业的执行,user-sh不需要在打印下一个提示符前等待后台作业的完成无论是否会有后台作业的执行,只要完成一个前台作业,便立即输出提示符。一个后台作业结束时,user-sh应当在作业执行结束后立刻打印出一条提示信息,后面会在命令语法分析程序中介绍相应的语法来支持后台作业。 user-sh通过处理组合键实现前/后台作业切换: Ctrl+Z 产生SIGTSTP信号,这个信号不是挂起user-sh,而是让user-sh挂起在前台运行的作业,如果没有任何前台作业,则该特殊键无效。 Ctrl+C 产生SIGINT信号,这个信号不终止user-sh,而是通过user-sh发出信号杀死前台作业中的进程。如果没有任何前台作业,则该特殊键无效

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值