您的位置:首页 > 运维架构 > Shell

247 MIT6.828 hw0-shell.c

2017-02-24 18:14 411 查看

MIT6.828 hw0

前一阵子面试时候新公司的小领导让我把c的知识捡回来,正好最近在跟MIT的操作系统课程。这篇博客是在网吧写的,中间还打了2盘dota2,女朋友一出差简直为所欲为…

1.从main开始

逻辑很清晰,调用
getcmd
从stdin获取命令,如果是
cd
命令,那么使用
chdir
这个系统调用,否则调用
fork1
新建子进程,用
parsecmd
获取命令,并
runcmd
执行命令

int main(void) {
static char buf[100];
int fd, r;

// Read and run input commands.
while(getcmd(buf, sizeof(buf)) >= 0){
if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
// Clumsy but will have to do for now.
// Chdir has no effect on the parent if run in the child.
buf[strlen(buf)-1] = 0;  // chop \n
if(chdir(buf+3) < 0)
fprintf(stderr, "cannot cd %s\n", buf+3);
continue;
}
if(fork1() == 0)
runcmd(parsecmd(buf));
wait(&r);
}
exit(0);
}


chdir是个系统调用

2.getcmd

这里参数buf是个字符数组,nbuf是字符数组长度

注意:

1.
fileno
获取stdin得文件描述符fd

2.
isatty
判断上面的fd是不是终端,即程序是不是从shell启动

3.
memset
初始化数组为0

4.
fgets
从stdin读取字符,每次最多读(nbuf-1)个字符,只不多不能超过一行

int getcmd(char *buf, int nbuf) {

if (isatty(fileno(stdin)))
fprintf(stdout, "6.828$ ");
memset(buf, 0, nbuf);
fgets(buf, nbuf, stdin);
if(buf[0] == 0) // EOF
return -1;
return 0;
}


3.fork1

perror(s) 用来将上一个函数发生错误的原因输出到标准设备(stderr)。

int fork1(void) {
int pid;

pid = fork();
if(pid == -1)
perror("fork");
return pid;
}


fork是个系统调用,分叉函数,子进程返回0,父进程返回子进程标记,出错返回-1

4.parsecmd

参数 s 是个字符数组

1.
parseline
获取命令

2.
peek


struct cmd* parsecmd(char *s) {
char *es;
struct cmd *cmd;

es = s + strlen(s);
cmd = parseline(&s, es);
peek(&s, es, "");
if(s != es){
fprintf(stderr, "leftovers: %s\n", s);
exit(-1);
}
return cmd;
}


这里注意
es = s + strlen(s);
,因为s是数组的首地址,数组的话就是相当于s[0],strlen(s)的结果是计算变量的全部元素,包含最后一个结束符”\0”。最后一个是结束符。

4.1 parseline

struct cmd* parseline(char **ps, char *es) {
struct cmd *cmd;
cmd = parsepipe(ps, es);
return cmd;
}


4.2 peek

int peek(char **ps, char *es, char *toks) {
char *s;

s = *ps;
while(s < es && strchr(whitespace, *s))
s++;
*ps = s;
return *s && strchr(toks, *s);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息