命令解释器的设计本说科毕业论文

上传人:仙*** 文档编号:148013690 上传时间:2022-09-03 格式:DOC 页数:29 大小:942.30KB
返回 下载 相关 举报
命令解释器的设计本说科毕业论文_第1页
第1页 / 共29页
命令解释器的设计本说科毕业论文_第2页
第2页 / 共29页
命令解释器的设计本说科毕业论文_第3页
第3页 / 共29页
点击查看更多>>
资源描述
目 录摘 要1前言21 绪论31.1 Shell的定义31.1.1 UNIX Shell31.2 shell的历史41.3 shell的职责42开发环境和开发工具介绍62.1开发环境-Ubuntu62.2开发工具-GCC63 模拟shell设计73.1简单shell设计思想73.2复杂shell设计思想83.2.1 作业及作业前后调度实现方法83.2.2进程组、会话与终端93.2.3命令行103.2.4 、bg、fg等信号的思想103.2.5 管道113.2.6重定向114 Shell的实现134.1数据结构134.2 程序结构134.2.1初始化环境134.2.2解析命令144.2.3查找外部程序154.2.4执行命令164.2.5管道174.2.6作业控制命令185 结束语20致谢21参考文献22附录2326Linux命令解释器的设计摘 要:随着Linux系统使用的越来越广泛,越来越多的人开始深入的研究Linux,特别是对Linux shell的研究是对Linux研究最主要的部分。本文主要是研究了对shell的功能的一些认识,而且对shell的列表,管道,输入重定向和输出重定向等命令功能进行了实现,可以对shell命令解释器进行更加全面的认识和充分的了解,而且在shell命令解释器中执行正确的命令,从而对它的原理,方法等在程序中必须用到的知识原理有比较清楚的认识,最后通过对每个功能的详细分析,进而编写出恰当实现各个功能的代码,从而做成一个Shell命令解释器。并且,在嵌入式领域中,与人们的需求相比,硬件的资源是微不足道的。这就意味着我们把不多的资源利用完成很多的需求,而嵌入式的设计在PC上编程是有很大不同的,它其实只需要一个很大程序的比较小的一方面就可以满足它的需求,因此我们必须把一些无用的程序删掉来换成空间。在嵌入式领域中就像传统的K shell,C shell,Bourne shell等大型的shell程序就会令硬件方面的东西很少。因此我们需要一个更符合嵌入式系统中使用的Shell。关键词:Shell;程序;设计与实现;嵌入式;LinuxAbstract:Accompanied by the popularize of the Linux,more and more peopleare doing deeply study in it.The study of shell is the most important thing when study the Linux.It mainly includes the understand of some knowledge and function of the micro linux shell.Through the study of the orders in the shell like list,pipe,input redirect and output redirect,readers can have a thorough sense about the shell and learn to use these orders accurately in shell which play an important role in programming later.Code accurately and achieve a simple shell with the functions above after analyzing the details of every functions module.Moreover,in the embedded field,the hardware resources are limited,but demand is unlimited.This means they have to use limited resources to accomplish a variety of needs and embedded design and programming in the traditional PC,is very different ,and it often requires only a small part of a large program on meet its needs,so we had to cut out a number of useless programs in exchange for space .In the embedded field,as the traditional K shell,C shell,Bourne shell and other large-scale shell program will make our hardware resources are stretched.So we need a more suitable for embedded systems used in the shell,this is my another objective of this design.Key words:Shell,Process,Design,Design and achieve,embedded,Linux前言shell作为Linux系统的最外层的部分,为使用者提供必备的接口。Shell作为用户和Linux内核之间的接口程序,起着一个桥梁的作用,假如把Linux内核当做是一个球心,那么shell就是球体的表面。从shell向Linux发出命令时,内核会对该命令做出相应的解释。本论文就是模拟一个shell命令解释器,包括:管道、内部命令、外部命令、重定向命令。管道是Linux支持的最初Unix IPC其中的一个,具有这一些特点:管道是半双工的,里面的数据只能单向的流动;当双方需要通信时,要创造出来两个管道;但是只能用于父子进程和兄弟进程之间(具有亲缘关系的进程);其实就是他们自己独自组成一种的文件系统,这个文件系统是独立的:管道相对于管道两端的进程来说,就是独立的文件,它不是一般的文件,它并不属于一种文件系统,而是自己有自己的特点,独自构成一种文件系统,而且只是在内存中。当写数据时一个进程向其中一个管道中写的数据会被管道另一头的进程读出,而且写入的数据每次都在管道缓冲区的最后,并且每次都是从缓冲区的首端读数据。每当执行shell命令行时一般会打开三个标准文件,这三个标准文件就是标准输入文件(stdin),一般对应用户所用的输入键盘;标准输出文件(stdout)和标准错误输出文件(stderr),这两个文件都对应着用户所用的输出屏幕。进程将从标准输入文件中读取输入数据,将正确的数据输出到标准输出文件,将不正确的信息输出到标准错误文件中。输入重定向,顾名思义,就是所把命令(或可执行程序)的标准输入重新定向到自己所认定的文件中。也就是说,输入不一定要来自键盘,可以来自一个自己指定的文件。输出重定向就是把命令(或可执行程序)的标准输出或标准错误输出重新定向到目标中。该命令的输出就不会在屏幕上显示,而是写入到自己的目标文件中。Shell是一个命令解释器,它就是把用户输入的命令进行重新解释而且把这些命令送到内核中。不止如此,Shell对命令的编辑有自己相对应的编程语言,但是灵活的是用户自身编写由shell命令组成的程序也是允许的。Linux像windows一样提供了很多可视化界面有窗口、图标和菜单,大部分控制都是通过鼠标来操作。现在在Linux中稍微流行的窗口管理器就是是KDE。而shell就像窗口管理器一样,它可以对系统灵活地进行各种管理。不同的Linux系统的用户有同的界面或Shell,来满足自己相应的Shell需要。同Linux本身一样,Shell也有多种不同的版本。目前主要有下列版本的Shell: Bourne Shell:由贝尔尔实验室研发的。 BASH:是GNU的Bourne Again Shell,是GNU操作系统上默认的shell。 Korn Shell:是对Bourne SHell的拓展,与Bourne Shell是互相兼容的。 C Shell:是SUN公司Shell的BSD版本。如果我们是经常使用UMX/Linux系统的研发人员,我们对shell的功能会有很深的认识和理解。1 绪论1.1 Shell的定义Shell是一种特殊的程序,如下图所示。他是用户与Linux系统内核之间的通道。内核在系统开机时将内存载入,关机后不再管理系统。它对进程,内存,文件和通信等都无时无刻的管理着。内核之外的自己编写的程序以及shell程序都保存在磁盘上,内核将这些程序加载到内存中运行,而且对它们运行完后进行系统清理。Shell是一个程序,在开机后系统启动。当用户开机并登陆后,系统不需要等待用户的命令会自动启动一个Shell。Shell会根据用户输入的命令后来执行命令:根据命令行的关键字来判断是那种命令,然后执行命令。当人们输入一组类似的命令是,希望会这些命令会自行的完成。这样的话,就可以把这些命令行输入到一个文件中,直接执行这个文件就可以完成那些命令的功能。1.1.1 UNIX ShellUNIX系统大都支持3种主流的shell,他们是BourneShell(也称为ATT shell)、C shell(也称为Berkeley)和Korn shell(Bourne shell的一个展集)。这三种Shell功能是很类似的,如果作为脚本的话,它们的还是有不同的。Bourne shell是标准的UXIN shell,用于系统管理。大部分系统管理脚本(如rc start和Stop脚本,shutdown)部是Bourne shell脚本。Bourne Shell的使用是非常简练的,而且很严谨,效率很高,它的命令提示符是$。C Shell完善了很多不同的功能,就像查询命令行历史,作业的前后台控制等。大部分的用户还是更倾向于C shell,其实管理者们还是倾向于Bourne Shell。由于类似的程序,使用Bourne Shell会效率更高。C shell默认的提示符是百分号(%)。Korn shell是ATT的David Korn开发的,它是Bourne shell的-个扩展集,在增强改进C shell的基础上,Korn shell添加了更多功能。Korn shell几乎完全向上兼容Bourne shell,所以老的Bourne程序在Kore shell中运行良好。Korn shell默认提示符是美元符号($)。Linux上默认的shell是GUN bash( Bourne Again shell),这是一种增强的Bourne shell,人们可以根据自己的工作环境进行编辑,因为它的功能有一部分还是有局限的,通过自己的编辑可以提高速度。如果用户想了解自己装的Linux是用的哪些Shell,直接在终端输入命令行:$cat/etc/shellls;即查看当前发行版本可以使用的shellLinux的环境中可以使用的Shell都在/etc/shells文件中。常用的版本包括bash(Bourne shell),tcsh(TC shell)金和ksh(Korn shell)。1.2 shell的历史Shell首个标准是在1979年由Stephen Bourne提出的,并且以该人的名字来作为名字。Bourne Shell是建立在Algol的程序的基础上的。在当时主要是对系统进程的管理比较方便,所以收到了很大用户的支持,但是在交互方面还是有所不足,有待完善。C Shell是由加州大学伯克利分校开发的,跟Bourne shell发行的不同,它是跟操作系统同步发布的。它的主要的开发人是Bill Joy。C shell就是完善了Bourne shell的不足,是用户与系统的交互更加的方便。而且,对于大型机的使用,有扩展了其他的功能,起到了很大的帮助,但是在小型机的使用还是效率很低。而且,即使在大型机上,它的速度也不如Bourne shell。由于不同版本的Shell发布,人们开始有选择的使用Shell,对于不同的Shell有自己的见解。20世纪80年代中期,AT&T的David Korn推出了Korn shell。其实Korn shell是对Bourneshell的一个拓展集,它在UNIX系统下可以运行的留长,还能在OS/2.VMS和DOS上运行的很顺利。Korn shell的优点就是可以不止可以再UNIX下使用,还可以在其它的系统下使用。由于Korn shell是对Bourne shell的拓展,由学习了C shell的优点,所以用户数很多。随着Linux的发展,Bourne Again shell (bash)开始流行起来。Bash是Linux操作系统默认上的shell。它的设计符合了IEE POSIX P1003.2/IS0 9945.2 shell和工具标准。bash又增加了很多新的功能:命令行历史与编辑、目录栈、作业控制、函数、别名、数组、整数运算(底数可以是2-64),还增加了一些Korn shell的功能,如扩展的元字符,select循环和let命令等。1.3 shell的职责Shell的主要功能就是根据用户的输入的命令行,来判断这是哪种命令,并且通过关键字来分解,比如空格,如果判断出来有不能识别的字符,shell会自动替换该字符。Shell处理I/O和后台进程,然后shell会自动搜索该命令,并开始执行。Shell的另外的重要的作用就是对用户环境进行设定,这往往是刚开始就是初始化的时候就已经进行了。在初始化的文件中有很多变量,根据不同的程序来设置相应的变量,所以用户在使用起来还是比较方便的。KornBash shell和C/TC shell还提供了其他的专门的功能:历史添加、别名、设置内置变量可以阻止用户对文件进行损坏或不小心退出,告诉用户作业已经结束。Shell还能用作编程语言来使用。2开发环境和开发工具介绍2.1开发环境-UbuntuUbuntu比较受欢迎的原因就是,它是完全像社会人们开放的,并且希望人们对系统进行完善并且是一些编程爱好者们共同开发的系统,所以Ubuntu目前是并将永远是免费的。但是,它还是需要成本的,它并不是无拘无束的可以自由的使用,使用的前提是对于社会来说,它是有益的,并不是恶意的使用它,人们可以随时下载,更正编写自由软件的权利。所以,它在技术层面上是所有人的结晶,是让很多开发者的各种想法融于一身的软件。所以该软件随着时间的推移,使用起来会更加的方便和高效。这就是自由软件的优点,也是大家都推崇的原因。2.2开发工具-GCCGNU C编译器是一个非常优越的编译器,它在Linux等系统的运行是非常重要的,可以说,这个编译器是效率很高的编译器,也是大多数开源系统的使用的最多的编译器。最初,GCC被认为是GNU C Complier的缩写。经过10多年的发展,GCC不仅支持C语言,还支持Ada、C+、Java、Objective C、Pascal、COBOL等开发语言。但是Gcc已经不只是一个但单纯的编译器了,人们已经将它的功能扩展到很多的语言上。GCC也变成GNU Co mpiler Collection(即GNU编译器族)的缩写。目前,GCC在人们的努力下,在所有的硬件平台上的使用都很方便,而且编译的过程也是十分简练,使用时可以通过自己的控制来灵活的使它在任意一个编译阶段停止,由于Unix的可移植性较高,几乎所有的Unix系统上都能看到GCC编译器,所以随着时间的流逝,人们会更加利用这个编译器,会更加的完善编译器。3 模拟shell设计3.1简单shell设计思想当我们知道Shell是如何使用的,我们也就可以开始编写一个自己的shell编译器了,起初编写时可以从简单的入手,最初的shell编写的思维可以分成下而几个方法: a) 用户在终端输入命令行,然后从而获取命令的内容。 b) 判断是内部命令还是外部命令。 c) 根据命令的不同,来调用相应的程序。对于外部命令执行相应的文件。 d) 循环执行上面一个过程。内部命令:内部命令由shell程序实现。如exit、cd、pwd、fg/bg等等,其实Linux的内部命令并不是那么多,并且很多的内部命令我们是几乎不用的,所以实现简单的内部命令还是比较少的。外部命令:外部命令其实不像我们想的很复杂,其是一个独立的应用,可以单独的是一个执行文件,也可以都集成在一个文件中的不同函数中。但是对于外部命令的编写还是比较复杂的。简单的shell流程图如图2.1所示:3.2复杂shell设计思想我们要从简单的开始入手,然后开始慢慢的了解和学习复杂的shell,刚开始要对命令进行分析然后判断前后台调度(&)、重定向(、)和管道(l)等,最后才判断命令是什么属性,才能继续往后面执行。3.2.1 作业及作业前后调度实现方法在系统中,进程的运行的状态是可以切换的。有一些我们不太使用的但是又不得不运行的程序就可以放到后台来运行,这样就可以不用在屏幕上有很多程序了,后台的程序也可以称作是后台作业。但是有一些作业是我们必须要自己看到运行的结果,这就是前台作业。图2.2就描述了各种进程和作业在操作系统中运行的一些状态。当执行如下两条命令时:$proc1|proc2& $proc3|proc4|proc5,进程会分为三个进程组。图2.3为命令执行时它们进程状态的不同,其中procl和proc2属于同一个后台进程组中的进程,二proc3、proc4、proc5被Shell放到同一个前台进程组,在他们当中,每一个进程都是这个进程组的组进程,Shell调用wait等待它们运行结束。一旦运行完成,shell就就调用tcsetpgrp函数将本身自己放到前台来等待下一步命令是什么操作。3.2.2进程组、会话与终端一个对话期,有它自己对应的控制的终端( controlling terminal)。在控制终端与对话期中间会建立一个进程,这个进程就叫做控制进程( controlling process)。图2.4为它们之间是互相怎样作用的。在一个对话期当中,有几个进程组称为前台进程组,还有个至少一个的在后台运行的进程组,前台进程组负责对输入进行接收。Shell中的对于作业的前后台的切换就是前台进程组和后台进程组的切换。如果一个命令中带有一些&符号的进程组那这个就是后台进程组。当对话期中仅仅有唯一一个控制终端,那么就有一个前台进程组,其它的任何进程组都是作为后台的进程组,不管什么时候进行作业的中断,都会是信号退出和中断。会话、进程组与进程的之间的关系如图2.5所示。3.2.3命令行用户一般在输入命令时,都会在提示符后面,那么这一行命令就叫做“命令行字符串”,shell用一个数组保存字符串,当这个作业运行完成后,shell才会释放保存的空间,也包括后台的作业和挂起的作业。这个标识符是来标记储存该作业的数据结构的作用,每个命令行字符串的内容都包含在该数据结构中,所以说,这个数据结构还是很重要的。当该作业运行完成后,shell就删掉数据结构,释放空间。标识符可以循环使用。但是如果这些命令行字符串是内部命令,那么就没有必要建立该作业的数据结构,因为本来就已经在shell程序中了,没必要在多此一举了。3.2.4 、bg、fg等信号的思想与本系统的任务有关的命令(内部命令):jobs、fg、bg等。1.被用到一个命令的最后,表示禁止命令在后台执行。2. ctrl+z可以将一个前台的命令暂停并且将该命令放到后台。3. jobs查看当前有多少在后台运行的命令。4. wait%作业号则是使该作业不再继续运行,只有后台作业执行完成后才可以。也可以后跟一个进程号作为参数。无:指一个前台作业 前台作业,该作业是终端用户进行交互命令和接受信号,在前台执行 将制定的作业号存储到该指针的链表中 作业数处理numProgs、runningProgs(加)有:表示为后台作业(可以有多个) 后台作业,该作业与终端交互命令和接受信号,但是在后台执行 将制定的作业号存储到该指针的链表中 作业数处理numProgs、runningProgs(加)后台的运行机制与前台的运行机制的不同就是前台要等待子进程的完成从而才可以停止父进程的操作。后台运行时可以在父进程中进行操作。fg命令:将后台进程发送信号切换到前台来,即用tcsetpgrp获取终端判断进程是否退出并阻塞父进程,调用waitpid等待。处理作业数numProgsrunningProgs,stopedProgs(减),正常退出时Jobid=0bg命令:让后台作业仍在后台运行,但是父进程继续运行,处理作业数numProgs,runningProgs,stopedProgs(减),正常退出时Jobid=0。jobs命令:对作业的状态进行判断并且输出该状态的信息,如running,done,stopped running的含义: runningProgs 0 stopped的含义:runninoProgs= stoppedProgs done的含义:runningProgs=03.2.5 管道管道是Linux支持的最初Unix IPC形式之一,具有这一些特点:管道是半双工的,管道当中的内容是从一个方向向另一个方向进行;所以当两方开始通信时,要把两个管道创建起来;然而它仅仅可以用于父进程和子进程或者两个兄弟进程之间(具有亲缘关系的进程);独自组成一个相互没有关联的文件系统:其实管道可以看做是一个文件,但是与其它普通文件不同的是它并不属于一种文件系统,而是自己有自己的特点,独自构成一种文件系统,而且只是在内存中。数据的读出与写入:一个进程只能向一个管道中的一头写入数据,管道另一头的进程会读出这个数据内容,这些写入的数据每次都会放在管道缓冲区的最后,但是读数据时必须要从从缓冲区的头部开始读数据。在输入命令时要用“|”将两个命令分开,系统就会自动从左边的命令的输出当做右边的命令的输入。当我们一直使用管道命令时,第二个命令的输出同样会作为第三个命令的输入,以此类推,管道方便了我们一直输入相同的命令的,可以直接调用相应的文件来查看命令。管道相关函数简介编写程序时,管道的两端,用fd0以及fd1来表示,管道的两端只能有固定的作用,不能混用。就是说管道的一端只能用于读的作用,用fd0表示,将其称为读端;同样,管道的另一端则只能用于写的作用,由fd1来表示,将其称为写端。但是如果当我们从管道的fd1进行读取数据时,或者向管道fd0用于输入数据的作用,那么就会发生错误,管道是严格的按照相应的规则进行的。一般文件的大多数的I/O函数都可以当做用于管道的函数,如close、read、write等等头文件:#include函数原型:int pipe(int fd2)函数传入值fd2:管道文件的描述符,然后就可以判断返回值:成功返回0,失败返回-1。3.2.6重定向重定向就是当执行shell命令行时一般会打开三个标准文件,即标准输入文件(stdin),一般对应终端的输入键盘;标准输出文件(stdout)和标准错误输出文件(stderr),这两个文件都对应着终端的输出屏幕。进程将从标准输入文件中读取输入数据,将正确的数据输出到标准输出文件,将不正确的信息输出到标准错误文件中。 一个程序命令后可能还跟有元字符“”,它们是重定向符,而在重定向符号后面还跟着一个文件名。在“”的情况下,程序的输出被重定向到一个指定的文件中。如果输入文件不存在,则认为是出现了错误。4 Shell的实现4.1数据结构在这次设计中,首先是建立了循环数组和链表数组,都用于history命令,用数组来保存以前曾经输入的命令字符。对链表的操作必须首先把作业用链表存储起来。首先定义链表的节点: typedef struct NODE pid_t pid; /进程号 char cmd100; /命令名 char state10; /作业状态 struct NODE *link; /下一节点指针 NODE; NODE *head.*end定义head指针来指向链表的表头,用end指针来指向链表的表尾。4.2 程序结构这四种不同类型的命令的执行是不一样的,但是每种命令的程序都有着相同的操作步骤:初始化的环境,显示命令提示符,获取并判定用户输入的命令,解析命令,最后就是寻找命令这几个步骤,如下图所示:4.2.1初始化环境在刚开始写程序的时候,需要对几个环境变量进行初始化的工作。比如将你所需要的查找的路径放入数组envpath中,对history和jobs的头指针和尾指针等进行相应的初始化。初始化的工作在程序中主要是由函数init_environ来进行的。void init_environ()int fd,n,i;char buf80;if(fd = open(myshell_profile,O_RDONLY,660) = -1)printf(init environ variable errorn);exit(1);while (n = line(fd,buf)getenviron(n,buf);envhis.start = 0;envhis.end = 0;head = end = NULL;在上面的程序中我们看到函数打开一个名字是myshell_profile的自己编写的文件,这是一个刚开始的配置文件,用户自己把配置的路径写到这个文件中。然后调用了另外两个函数line (fd,buf和getenviron(n,buf)。line(fd,buf)的作用是读取行的信息到buf中。getenviron(n,buf)的主要作用是读取line(fd,buf)读取的命令,然后用冒号分隔开buf中的信息,将命令各自放在envpath中,等待后面查找命令时在envpath中寻找命令。这样命令前期初始化工作就已经完成了。然后初始化history命令中链表的头指针和尾指针,将envhis.start和envhis.end的值置为0,同样将jobs命令中的头指针和尾指针分别指为空,head=end=NULL。到现在为止,我们所做的程序的前期准备工作已经大概做完了。然后,就会进行while循环,与普通的shell命令解释器是一样的,当命令之行结束,或者将这个命令放在后台执行,用户就可以重新输入新的命令行,shell可以重头开始重复原来的工作。4.2.2解析命令解析指令时,对输入到数组input的命令内容完成解析,然后得到该命令和对应的参数。shell中的命令分成4种:重定向命令,普通命令(外部命令),管道命令和内部命令。但是由于管道和重定向命令比较复杂,所以对管道和重定向命令需要另外来处理。for(i = 0,j = 0,k = 0;i=input_len;i+)if(inputi = |inputi = |)if(inputi = |)pipel(input,input_len);add_history(input);free(input);elseredirect(input,input_len);add_history(input);free(input);is_pr = 1;break;该程序中用for循环将带有字符“”,“”和“|”符号的管道和重定向命令进行另外的完成。然后定义一个is_pr,这是管道和重定向的命令标志,置为1。然后分别调用redirect(input,input_len)和pipel(input,input_len)两个函数来处理这两类命令。对于普通的命令,当检测到is_pr的值是0的时候,就进行下面的程序,下面的代码就是主要普通命令和内部命令进行处理。for(i = 0,j = 0,k = 0;i=input_len;i+)if(inputi = |inputi = 0)if(j = 0)continue;elsebufj+ = 0;argk = (char *) malloc(sizeof(char)*j);strcpy(argk+,buf);j = 0; elseif(inputi = & & inputi+1 = 0)is_bg = 1;continue;bufj+ = inputi;上面程序的for循环的作用就是对input数组中的命令进行分析。当用户输入空格时,就会区分命令和参数,如:“ls -l”。这个例子的作用就是将这条命令的ls首先存储到arg0,而参数-l则存储在arg1。但是对于input数组的解析是要符合以下的规则的:以空格分段,分别放在argi中。当这个for循环运行过后,数组argv0中的内容就非常重要了,可以对数组arg0的内容来分辨输入的到底是内部命令还是外部命令。判断是内部命令的话,就会执行相对应的操作。4.2.3查找外部程序当我们检测到的命令不是内部命令,也不是重定向命令和管道命令,就可以判断是外部命令了。对于外部命令的处理就是查找该命令的执行文件。if(is_pr = 0)argk = (char *)malloc(sizeof(char);argk = NULL;if(is_founded(arg0) = 0)printf(This command is not founded!n);for(i = 0;i=k;i+)free(argi);continue;is_founded函数就是用来来判断输入的外部命令的文件是不是已经存在。函数如下:int is_founded(char *cmd)int k = 0;while(envpathk!=NULL)strcpy(buf,envpathk);strcat(buf,cmd);if(access(buf,F_OK) = 0)return 1;k+;return 0;当我们对程序初始化的时候,我们已经将命令以及其对应的路径已经存储到数组envpathi中,所以下面的工作就比较好做了,就直接在相对应的路径下查找和判断输入命令到底有没有存在。如果找到返回l,没有则返回0。当我们判断的时后就用到了access系统调用函数。格式 #include int access(const char *pathname,int mode); 参数说明 pathndme是文件名称。我们要判断mode的属性,可以取它们之间的组合或者是直接取值,文件可以读用R_OK表示,文件可以写用W_OK表示,文件可以执行用X_OK表示,文件存在则用F_OK表示,当函数的返回值为0时,测显示测试成功,否则返回值为-1。当输入的命令被查找到时,就把相应的命令和路径放到数组buf中。然后就直接执行命令。4.2.4执行命令当我们查找到命令文件时,就可以继续执行该命令内容了。这时,首先要新建一个子进程,在该子进程中执行那个命令。fork创建一个新的子进程的时候,该进程会把其对应的父进程的堆栈和数据都继承下来,以及用户的ID、环境变量等,还有工作的目录等等。其实Linux会使用一个称作COW的技术,该技术是当中间有一个进程如果想要修改所复制的空间时,才会真正的做复制动作。子进程的数据发生变化时,父进程的数据是不会由于子进程当中的数据变化而改变自身的数据的。当一个子进程创建完成后,父进程中的pid号就是其子进程的真正的ID号,但是创建失败时,就会返回值为-1。 这一段程序如下:If(pid = fork() = 0)Execv(buf,arg);ElseIf(is_bg= 0)Waitpid(pid,&status,0);这几行代码运行后就可以执行外部命令。这里用到了两个系统凋用函数execv和waitpid。函数waitpid格式:pid_t waitpid(pid_t pid,int *status,int options);当一个命令是前台执行的,那么其父进程则必须执行函数waitpid,而且必须等待子进程,只有当子进程结束后,父进程才可以执行。后台执行恰恰不需要等待子进程的完成就可以继续执行,就不需要waitpid。这就是前后台命令的差别。waitpid所等待的子进程由它的第个参数pid决定。因为pid就是他父进程中子进程的id号。只有当其对应的子进程执行结束后,父进程才可以继续运行。程序写到这,那么一个比较简便的shell命令解释器基本写完了,但是它只局限于内部命令和外部命令,为了完善它的功能,还需要增加很多东西和代码。但是基本的shell的思想大致就是这样的。4.2.5管道函数intpipel就是实现shell管道程序的函数。同以上的步骤差不多,该函数也需要命令的解析,寻找文件,和执行以及释放空间。基本的思想是不会改变的。其实对于管道,跟重定向是由异曲同工指出的,都需要系统调用函数来是子进程的文件描述符改变,就是dup2函数。初始化文件描述符IPE:#define NO_PIPE -1#define FD_READ 0#define FD_WRITE 1for(i = 0;i=10;i+)fdiFD_READ = NO_PIPE;fdiFD_WRITE = NO_PIPE;其中fdiFD_READ和fdiFD_WRITE都是int类型的文件描述符。上面已经提到过,管道是有相应的读端和写端,所以fdi0是管道读端的入口,fdi1就是管道写端的入口。用fdiFD_READ和fdiFD_WRITE是为了方便阅读。这个循环初始化了10对指向NO_PIPE(-1)的文件描述符。1)建立管道我们在这里分别定义了pipe_out和pipe_in这两个文件描述来描述管道的写端和读端。从管道的读端进行输入,写端进行输出。我们用pipe_in来表示管道的读端:/*将pipe_in指向管道的读端*/if(i != 0)pipe_in = fdi-1FD_READ;else pipe_in = NO_PIPE;/*将pipe_out指向管道的写端*/if(i != li_cmd)pipe_out = fdiFD_WRITE;把这两段程序都在一个for的循环来使用,然后将pipe_in指向管道的读端(除了首命令),将pipe_out指向管道的写端(除了最后一条命令)。因为管道已经建立完成了,然后进程的输出就写到管道当中,将标准输出直接重定向到管道的写端标准输入重定向到读端,最后我们就可以读到管道当中的数据了。if(pid = 0)if(pipe_in = NO_PIPE)close(pipe_in);if(pipe_out = NO_PIPE)close(pipe_out);if(pipe_out!=NO_PIPE)dup2(pipe_out,1);close(pipe_out);if(pipe_in!=NO_PIPE)dup2(pipe_in,0);close(pipe_in);execv(buf,argvi);elseif(is_bg = 0)waitpid(pid,NULL,0);close(pipe_in);close(pipe_out);管道命令就可以实现了。4.2.6作业控制命令作业控制的主要命令包括三个:jobs、bg和fg等。jobs命令jobs的实现,要用到链表。每次建立一个后台的作业或者当一个作业被挂起的时候,链表中会创建一个与其相对应的节点,因此,当用户执行一个命令,该命令是建立一个后台运行的作业,作业控制就要在该链表的末端创建一个节点,然后把作业的数据内容储存在该节点中。当用户输入jobs命令行时,然后就要把链表中的所有的作业信息都要显示到控制台中,还有作业号,运行状态和名字。bg和fg命令我们定义了一个Ctrl+Z函数,这个函数和fg、bg之间都是相关的,并不是毫无联系的在一起,Ctrl+Z就是暂停一个正在前台执行的任务,然后当我们输入bg命令,所对应的作业就会放到后台执行,并且使其处于暂停状态。相反的是,当输入fg命令时,就会把后台或者挂起的作业重新放在前台来执行。所以我们一定要利用好这三个命令之间的关系才能对作业进行有效的控制。在我们写程序的时候我们专门写了一个信号处理函数signal(SIGTSTP,ctrl_z),SIGTS TP是交互停止信号。当用户按下Ctrl+Z时,驱动程序就会向shell发送SIGTS TP信号。而信号处理函数signal可以捕捉到这个SIGTSTP信号。可以看到函数signal的设置:当收到SIGTSTP信号时,执行函数ctrl_z。编写的程序中,ctrl_z函数目的就是在链表中增加一个作业的节点,然后把该节点的状态修改为stopped,然后用一个系统调用函数kill传送一个SIGSTOP的信号到前台的作业,SIGTS TP信号的作用是停止一个进程,前台的作业受到这个信号后就会被挂起。当我们把前台的作业挂起之后,shell就会显示用户自己设置的命令提示符,就可以执行下一条命令,操作过程跟之前的一样,然后,前后台切换进程就完成了。但是当一个作业被挂起后,我们希望该作业在后台运行,那么我们就可以用bg%作业号把对应的作业有挂起状态修改到放到后台执行,就会调用bg_cmd函数。函数bg_cmd要做的工作是:用户输入一个作业号,然后函数就会遍历jobs链表,找到相对应的作业的节点,找到该节点信息所对应的进程号。然后利用kill向该进程发送一个SIGCONT信号,使该进程继续运行。当该进程受到这个信息后,就会继续运行,但是我们没有令父进程等待,所以该进程是在后台运行的。同样,如果我们希望一个作业在前台使用,就可以使用fg%作业号就可以完成。当我们使用该命令后,直接执行fg_cmd这个函数,。函数fg_cmd中,要做的工作是:这个函数会把输入的作业号在作业链表中找到该作业的节点,然后,就会从节点中找出该信息。然后利用函数kill向该进程发送一个SIGCONT信号。这个信号会使该进程继续运行。但是与bg命令的差别是,我们必须要在前台执行那个作业。因此,还要是父进程等待刚才的进程,才能完成任务。当我们使用fg、bg和Ctrl+Z时,就会有关对相应链表的节点操作,该命令是shell的高级命令,同样也是比较复杂的命令。我们所做的shell的命令解释器就做完了,其实工作还有很多没有做,但是最基本的功能已经做的差不多了。5 结束语1)本设计基本达到了设计目的。我们经过了这次毕业设计,基本上熟悉Linux的工作方式,以及其开发环境。2)这次设计的shell能完成基本的shell命令,对作业的前后台的切换,以及管道和重定向的部分也有了基本的完成。3)熟悉了shell的实现的流程,以及系统调用是怎么运行的,还有内核与shell的关系是怎样的。4)在编写的程序中用到了结构体,指针,链表等一些数据结构,所以对我在C语言的学习也有了很大的帮助,特别是解决了中间的一些困难。致谢走的最快的总是时间,来不及感叹,大学生活已近尾声,四年多的努力与付出,随着本次论文的完成,将要划下完美的句号。本论文设计在老师的悉心指导和严格要求下业已完成,从课题选择到具体的写作过程,论文初稿与定稿无不凝聚着老师的心血和汗水,在我的毕业设计期间,老师为我提供了种种专业知识上的指导和一些富于创造性的建议,老师一丝不苟的作风,严谨求实的态度使我深受感动,没有这样的帮助和关怀和熏陶,我不会这么顺利的完成毕业设计。在此向老师表示深深的感谢和崇高的敬意!在临近毕业之际,我还要借此机会向在这四年中给予我诸多教诲和帮助的各位老师表示由衷的谢意,感谢他们四年来的辛勤栽培。不积跬步何以至千里,各位任课老师认真负责,在他们的悉心帮助和支持下,我能够很好的掌握和运用专业知识,并在设计中得以体现,顺利完成毕业论文。同时,在论文写作过程中,我还参考了有关的书籍和论文,在这里一并向有关的作者表示谢意。我还要感谢同组的各位同学以及我的各位室友,在毕业设计的这段时间里,你们给了我很多的启发,提出了很多宝贵的意见,对于你们帮助和支持,在此我表示深深地感谢!参考文献1 Linux kernel development Robert Love著3rd ed.北京 :China MachinePress,20112 Linux system programmingLinux系统编程 Robert Love南京 :东南大学出版社,20083 Linux操作系统内核实习: 英文版 / (美)加里纳特(Gary Nutt)著. - 北京: 机械工业出版社, 2002.64 操作系统课程设计 罗宇等 机械工业出版社 2005/95 UNIX Shell 范例精解 / (美).E奎格利Ellie Quigley著; 刘洪涛译. - 北京: 清华大学出版社, 2004.106 实战Linux编程精髓 / (以) A.罗宾斯Arnold Robbins著; 杨明军等译. - 北京: 中国电力出版社, 20057 Linux操作系统原理与应用 / 陈莉君, 康华编著. - 北京: 清华大学出版社, 20068 Linux内核设计与实现 / (美)R.洛夫Robert Love著. - 英文版. - 北京: 机械工业出版社, 2006 9 Linux C编程 / 李玉波, 朱自强, 郭军编著. - 北京: 清华大学出版社, 200510 Linux内核编程指南 / M.贝克Michael Beck等著; 张瑜, 杨继萍等译. - 北京: 清华大学出版社, 200411 Linux程序设计 / (美)A.罗宾斯Arnold Robbins著. - 英文版. - 北京: 机械工业出版社, 200512 Linux教程 / (美) S.萨瓦尔 Syed Mansoor Sarwar, Robert Koretsky, Syed Aqeel Sarwar著; 李善平, 施韦, 林欣译. - 北京: 清华大学出版社, 200513 Linux技术大全 / (美)R.皮特森Richard Petersen著; 陶华敏等译. - 北京: 机械工业出版社, 2002.114 Linux宝典 / (美) C.尼格斯Christopher Negus著; 徐小青 等译. 电子工业出版社, 200515 LINUX&UNIX程序开发基础教程 / (美)萨瓦(Sarwar)等著; 英宇,姚锋译. - 北京:清华大学出版社, 200316 操作系统实验指导 任爱华等 清华大学出版社 200417 操作系统辅导与提高 任爱华 清华大学出版社 2004附录主要程序#include #include #include #include #include #include #include #include #include #include #include #include mysh.h#define NO_PIPE -1#define FD_READ 0#define FD_WRITE 1main()/*声明函数*/int redirect();int pipel();int line();int is_founded();void init_environ();void getenviron();void add_history();void history_cmd();void cd_cmd();void jobs_cmd();void add_node();void del_node();void ctrl_z();void setflag();void bg_cmd();void fg_cmd();init_environ();while(1)char c,*arg20;int i = 0,j =
展开阅读全文
相关资源
相关搜索

最新文档


当前位置:首页 > 管理文书 > 施工组织


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!