Implement a Shell by yourself -- MIT xv6 shell


Implement a Shell by yourself -- MIT xv6 shell



这个其实是作为6.828的一个小课堂作业 ...

着重分析构建思想和过程,具体代码实现去github可以找到.


https://github.com/jasonleaster/MIT_6_828_assignments_2012/blob/homework1/sh.c


----------------------------------- 大家好,我是分割线 -------------------------------------------------------------------


这里主要实现了基础的三类命令

  • 可执行的程序命令
  • 重定向命令
  • 管道命令

实现的"基类" (原谅我用了这个词)就是struct cmd这个结构体就一个成员,用于记录命令的类型.

三类, ‘ ‘ 表示可执行程序 ‘|‘ 表示管道命令,  ‘<‘  和‘>‘ 表示重定向类型.

每一个类型分别继承基类,派生出对应的三类结构体 

struct execcmd

struct redircmd

struct pipecmd

技术分享

对于可执行命令,主要记录可执行程序的程序名字还有各种选项参数.所以会有 char* argv[MAXARGS]

对于重定向命令,主要记录 cmd 即触发这个重定向的程序比方说 ./a.out > tmp.txt

                         那么cmd就是记录的./a.out 重定向到那个文件的文件名 char *file指针指向这个文件名.

对于管道,           则主要记录管道左右两侧的命令


void runcmd(struct cmd * cmd);

这个函数是真正驱动调用实现shell的核心.负责调用系统接口函数 execv(), open(), close(), dup(), pipe()等等一系列函数,来完成我们既定的目标.

作业也就是补全这个函数.

这是个递归的函数!很有意思.

你会发现,shell的命令实现居然是递归的哈哈


这里是主函数:

技术分享

调用getcmd()在标准输入读取sizeof(buf)大小的字符,然后,写入到buf中.

那个 if(buf[0] .... )是判断你是不是输入了 cd命令 如果是把buf尾部赋值为0,这样buf看起来就是储存的一个字符串,

然后调用chdir() 更换当buf+3开始的字符串指定的路径.

接着continue继续读取命令啦...

如果你不更换路径了

我们就fork1()出一个子进程,parent process就一直等待子进程挂掉...等啊等..等啊等..


这个时候,子进程就开始调用parsecmd()去分析你输入的命令字符串咯...


技术分享

es指针指向字符串的末端,确切的说是空字符处

然后去调用 parseline(&s, es)

parseline() 看起来太弱了,就是一层简单的封装.实际核心函数还是parsepipe

技术分享



execcmd()返回一个struct cmd()结构体.

同样的*cmd()函数都会返回一个对应的 *结构体

值得特别强调好玩的事情是,你会发现这里 execcmd()返回的是一个 struct cmd* 指针

但是execcmd()函数确实申请的是一个struct execcmd()结构体.那么问题就来了..怎么会这样.

回过头去观察四种结构体的之间的关系你就会发现,这里巧妙之处就在于,他们的第一个成员都是相同的!

返回了一个"基类"指针.


技术分享





                               "骚年别闹~"

技术分享


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。