linux命令解释器的设计本科毕业论文(编辑修改稿)内容摘要:
unning, done, stopped running 的含义: runningProgs 0 stopped 的含义: runninoProgs= stoppedProgs done 的含义: runningProgs=0 管道 管道是 Linux 支持的最初 Unix IPC 形式之一,具有这一些特点:管道是半双工的,管道当中的内容是从一个方向向另一个方向进行;所以当两方开始通信时,要把两个管道创建起来;然而它仅仅可以用于父进程和子进程或者两个兄弟进程之间(具有亲缘关系的进程);独自组成一个相互没有关联的文件系统:其实管道可以看做是一个文件,但是 与其它普通文件不同的是它并不属于一种文件系统,而是自己有自己的特点,独自构成一种文件系统,而且只是在内存中。 数据的读出与写入:一个进程只能向一个管道中的一头写入数据,管道另一头的进程会读出这个数据内容,这些写入的数据每次都会放在管道缓冲区的最后,但是读数据时必须要从从缓冲区的头部开始读数据。 在输入命令时要用“ |”将两个命令分开,系统就会自动从左边的命令的输出当做右边的命令的输入。 当我们一直使用管道命令时,第二个命令的输出同样会作为第三个命令的输入,以此类推,管道方便了我们一直输入相同的命令的,可以直接调用 相应的文件来查看命令。 管道相关函数简介 编写程序时,管道的两端,用 fd[0]以及 fd[1]来表示,管道的两端只能有固定的作用,不能混用。 就是说管道的一端只能用于读的作用,用 fd[0]表示,将其称为读端;同样,管道的另一端则只能用于写的作用,由 fd[1]来表示,将其称为写端。 但是如果当我们从管道的 fd[1]进行读取数据时,或者向管道 fd[0]用于输入数据的作用,那么就会发生错误,管道是严格的按照相应的规则进行的。 一般文件的大多数的 I/O函数都可以当做用于管道的函数,如 close、 read、 write等等头文 件: include函数原型: int pipe(int fd[2])函数传入值fd[2]:管道文件的描述符,然后就可以判断返回值:成功返回 0,失败返回 1。 重定向 重定向就是当执行 shell 命令行时一般会打开三个标准文件,即标准输入文件 (stdin),一般对应终端的输入键盘;标准输出文件 (stdout)和标准错误输出文件 (stderr),这两个文件都对应着终端的输出屏幕。 进程将从标准输入文件中读取输入数据,将正确的数据输出到标准输出文件,将不正确的信息输出到标准 错误文件中。 一个程序命令后可能还跟有元字符“ ”或“ ”,它们是重定向符,而在重定向符号后面还跟着一个文件名。 在“ ”的情况下,程序的输入被重定向到一个指定的文件中。 在“ ”的情况下,程序的输出被重定向到一个指定的文件中。 如果输入文件不存在,则认为是出现了错误。 4 Shell 的实现 在这次设计中,首先是建立了循环数组和链表数组,都用于 history 命令,用数组来保存以前曾经输入的命令字符。 对链表的操作必须首先把作业用链表存储起来。 首 先定义链表的节点: typedef struct NODE{ pid_t pid。 //进程号 char cmd[100]。 //命令名 char state[10]。 //作业状态 struct NODE *link。 //下一节点指针 } NODE。 NODE *head.*end 定义 head 指针来指向链表的表头,用 end指针来指向链表的表尾。 程序结构 这四种不同类型的命令的执行是不一样的,但是每种命令的程序 都有着相同的操作步骤:初始化的环境,显示命令提示符,获取并判定用户输入的命令,解析命令,最后就是寻找命令 这几个步骤,如下图所示: 初始化环境 在刚开始写程序的时候,需要对几个环境变量进行初始化的工作。 比如将你 所需要的查找的路径放入数组 envpath[]中,对 history 和 jobs 的头指针和尾指针等进行相应的初始化。 初始化的工作在程序中主要是由函数 init_environ来进行的。 void init_environ() { int fd,n,i。 char buf[80]。 if((fd = open(myshell_profile,O_RDONLY,660)) == 1){ printf(init environ variable error\n)。 exit(1)。 } while (n = line(fd,buf)){ getenviron(n,buf)。 } = 0。 = 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 命令中链表的头指针和尾指针,将 和 的值置为 0,同样将 jobs 命令中的头指针和尾指针分别指为空, head=end=NULL。 到现在为止,我们所做的程序的前期准备工作已经大概做完了。 然后,就会进行 while 循环,与普通的 shell 命令解释器是一样的,当命令之行结束,或者将这个命令放在后台执行,用户就可以重新输入新的命令行, shell 可以重头开始重复原来的工作。 解析命令 解析指令时,对输入到数组 input 的命令内容完成解析,然后得到该命令和对应的参数。 shell 中的命令分成 4种:重定向命令,普通命 令 (外部命令 ),管道命令和内部命令。 但是由于管道和重定向命令比较复杂,所以对管道和重定向命令需要另外来处理。 for(i = 0,j = 0,k = 0。 i=input_len。 i++){ if(input[i] == 39。 39。 ||input[i] == 39。 39。 ||input[i] == 39。 |39。 ){ if(input[i] == 39。 |39。 ){ pipel(input,input_len)。 add_history(input)。 free(input)。 }else{ redirect(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(input[i] == 39。 39。 ||input[i] == 39。 \039。 ){ if(j == 0) continue。 else{ buf[j++] = 39。 \039。 arg[k] = (char *) malloc(sizeof(char)*j)。 strcpy(arg[k++],buf)。 j = 0。 } }else{ if(input[i] == 39。 amp。 39。 amp。 amp。 input[i+1] == 39。 \039。 ){ is_bg = 1。 continue。 } buf[j++] = input[i]。 上面程序的 for 循环的作用就是对 input 数组中的命令进行分析。 当用户输入空格时,就会区分命令和参数,如:“ ls l”。 这个例子的作用就是将这条命令的 ls 首先存储到 arg[0],而参数 l 则存储在 arg[1]。 但是对于 input 数组的解析是要符合以下的规则的:以空格分段,分别放在 arg[i]中。 当这个 for循环运行过后,数组 argv[0]中的内容 就非常重要了,可以对数组 arg[0]的内容来分辨输入的到底是内部命令还是外部命令。 判断是内部命令的话,就会执行相对应的操作。 查找外部程序 当我们检测到的命令不是内部命令,也不是重定向命令和管道命令,就可以判断是外部命令了。 对于外部命令的处理就是查找该命令的执行文件。 if(is_pr == 0){ arg[k] = (char *)malloc(sizeof(char))。 arg[k] = NULL。 if(is_founded(arg[0]) == 0){ printf(This mand is not founded!\n)。 for(i = 0。 i=k。 i++) free(arg[i])。 continue。 } } is_founded 函数就是用来来判断输入的外部命令的文件是不是已经存在。 函数如下: int is_founded(char *cmd) { int k = 0。 while(envpath[k]!=NULL){ strcpy(buf,envpath[k])。 strcat(buf,cmd)。 if(access(buf,F_OK) == 0) return 1。 k++。 } return 0。 } 当我们对程序初始化的时候,我们已经将命令以及其对应的路径已经存储到数组 envpath[i]中,所以下面的工作就比较好做了,就直接在相对应的路径下查找和判断输入命令到底有没有存在。 如果找到返回 l,没有则返回 0。 当我们判断的时后就用到了 access 系统调用函数。 格式 include int access(const char *pathname,int mode)。 参 数说明 pathndme 是文件名称。 我们要判断 mode 的属性,可以取它们之间的组合或者是直接取值,文件可以读用 R_OK 表示,文件可以写用 W_OK 表示,文件可以执行用 X_OK 表示,文件存在则用 F_OK 表示,当函数的返回值为 0 时,测显示测试成功,否则返回值为1。 当输入的命令被查找到时,就把相应的命令和路径放到数组 buf 中。 然后就直接执行命令。 执行命令 当我们查找到命令文件时,就可以继续执行该命令内容了。 这时,首先要新建一个子进程,在该子进程中执行那个命令。 fork 创建一个新的子进程的时 候,该进程会把其对应的父进程的堆栈和数据都继承下来,以及用户的 ID、环境变量等,还有工作的目录等等。 其实 Linux 会使用一个称作 COW 的技术,该技术是当中间有一个进程如果想要修改所复制的空间时,才会真正的做复制动作。 子进程的数据发生变化时,父进程的数据是不会由于子进程当中的数据变化而改变自身的数据的。 当一个子进程创建完成后,父进程中的 pid号就是其子进程的真正的 ID号,但是创建失败时,就会返回值为 1。 这一段程序如下: If((pid = fork()) == 0) Execv(buf,arg)。 Else If(is_bg== 0) Waitpid(pid,amp。 status,0)。 这几行代码运行后就可以执行外部命令。 这里用到了两个系统凋用函数execv 和 waitpid。 函数 waitpid 格式 : pid_t waitpid(pid_t pid,int *status,int options)。 当一个命令是前台执行的,那么其父进程则必须执行函数 waitpid,而且必须等待子进程,只有当子进程结束后,父进程才可以执行。 后台执行恰恰不需要等待子进程的完成就可以继续执行,就不需要 waitpid。 这就是前后台命 令的差别。 waitpid 所等待的子进程由它的第个参数 pid 决定。 因为 pid 就是他父进程中子进程的 id 号。 只有当其对应的子进程执行结束后,父进程才可以继续运行。 程序写到这,那么一个比较简便的 shell 命令解释器基本写完了,但是它只局限于内部命令和外部命令,为了完善它的功能,还需要增加很多东西和代码。 但是基本的 shell 的思想大致就是这样的。 管道 函数 intpipel 就是实现 shell 管道程序的函。linux命令解释器的设计本科毕业论文(编辑修改稿)
相关推荐
汽车发展的进程。 中国的天然气汽车进入了快速发展期。 截至 2020 年底,全国已有 30 个省市自治区的 80 多个城市推广天然气汽车。 其中 16 个重点推广城市 (地区 )共发展天然气汽车 万辆,比 2020年增长近 8 万辆;建成天然气加气站 555座,比 2020年增加 75座。 作为天然气汽车的一种,液化天然气汽车近年 来 也得到一定发展。 现今采用高压直喷技术的 LNG汽车
..................................................... 54 第八章 总结与展望 ............................................................................................. 55 论文工作回顾 ............................
发展,这将使产业结构得到优化调整,起到减少投资,保护环境的效果,对经济的发展产生积极作用。 提高人民生活质量的需要: (2)改善环境的需要: 目前 该地区 大部分 用户的能源以煤 、油 为主,产生了大量的烟尘和有害气体。 利用天然气这一高效清洁能源,解决了城区大量茶水炉、食堂灶、餐饮煤炉等居民生活及 汽车尾气 市场消费污染源造成的局部环境严重污染又缺少有效治理措施的矛盾。 2 园区 概况 园区
TIN模 块 1模 块 21 6 1 6L E D1 6 1 6L E D1 6 1 6L E D1 6 1 6L E D1 6 1 6L E D1 6 1 6L E D1 6 1 6L E D模 块 3模 块 47 芯 连 接 线7 芯 连 接 线7 芯 连 接 线7 芯 连 接 线 图 “ 你 ” 的字模 256个点由 32 个字节组成( 32 8=256),字模可以通过专门软件获得。
社 会救助体系基本形成。 全民医保基本实现,城乡基本医疗卫生制度初步建立。 保障性住房建设加快推进。 加强和创新社会管理,社会保持和谐稳定。 国防和军队建设开创新局面。 中国特色军事变革取得重大成就,军队革命化现代化正规化建设协调推进、全面加强,军事斗争准备不断深 化,履行新世纪新阶段历史使命能力显著增强,出色完成一系列急难险重任务。 港澳台工作进一步加强。 香港、澳门保持繁荣稳定
稳压电源原理 小功率稳压电源由电源变压器、整流电路、滤波电路和稳压电路四个部分组成。 无线 LED 显示屏的设计 13 图 1 220V 交流转成 5V 直流电源原理图 从图上看 ,变压器输入端经过一个保险连接电源插头 ,如果变压器或后面的电路发生短路,保险内的金属细丝就会因大电流引发的高温溶化后断开。 变压器后面由 4 个二极管组成一个桥式整流电路,整流后就得到一个电压波动很大的直流电源