标签:
这是6.828第一节的一个小作业,就是实现一个shell,大部分的源码都给了,但是编译一下发现很多bug和warning,所以需要读懂源代码然后自己改。
这次作业的重点在于理解和体会shell是怎么实现和构建的,尤其要体会的是unix系统中管道和重定向
关于shell实现的一些基本原理请看xv6-book chapter0A
shell需要保证在任何时候都有三个打开的文件描述符,他们是控制台的默认文件描述符
惯例是从文件描述符0读入,从文件描述符1输出(标准输出),从文件描述符2输出错误
首先是gecmd读取命令
命令有5类:
整个函数的核心函数有两个,一个是parsecmd,一个是runcmd
当读入命令的时候,首先进行解析
parsecmd的核心函数是parseline
这个函数是递归的,执行流程:
下面是代码
上面的Listcmd函数其实非常简单,就是将多个命令连接成一个链表
backcmd函数更简单,就是生成一个指向新命令的指针
而真正的核心函数是parsepipe
parsepipe的函数写的很简短,其中第一个parseexec函数是根据输入命令中第一条可执行命令生成对应结构体
然后针对剩下的部分递归调用parsepipe函数,递归的生成命令
其实pipecmd和listcmd结构体是一样的
区别在于实际执行的时候
如果是listcmd,那就是一条一条的执行,执行完上一条执行下一条
下面的递归写法就是这样的
管道命令
而pipecmd就不能这样写,因为是要生成管道而且要将管道绑定到某些端口的输入输出的
首先生成一个管道
然后fork一个子进程出来,将原本的输出文件描述符关闭之后,将输出文件描述符绑定到管道的输出端上,然后执行左边的命令
对于右边的命令是一样的,这样就可以将输入输出组合起来了
这里需要注意的是为什么在两个子进程内部都需要把管道描述符关掉
重定位命令是比较有意思的
看一下重定位命令的执行过程
这里执行过程是,首先关掉某文件描述符,如果重定向是>,关掉的是输出,否则是输入,释放文件描述符
然后打开指定的文件(代码一开始是错的,没有制定flag,没有权限新建或者打开),赋予刚刚释放的文件描述符
在上面的代码中,myexecv是我自己写的,因为比如要执行ls函数,必须要输入/bin/ls才行,为了添加默认的路径,我将输入命令进行了处理
如果说有自带的路径,直接执行就好了,否则添加默认路径/bin/
list命令
实际上就是一次输入多个不相关的命令,依次执行
处理的方式也比较简单
listcmd如下
总结
在第领章的时候,有这么几句话
一开始看的时候我并不太懂,现在体会到了,从XV6的shell设计里,可以看出,内部只使用少量的通用接口,但是通过组合,使用管道,重定向等,可以实现很复杂强大的功能
另外,这里面的数据结构设计的也很棒,包括命令的链表式连接,pipe的树状执行等
MIT 6.828-operating system engineering homework: shell
标签:
原文地址:http://www.cnblogs.com/bdhmwz/p/4922426.html