xv6-----shell

这是操作系统原理课程的第一个编程作业,补全shell的功能。

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

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

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

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

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

struct execcmd

struct redircmd

struct pipecmd

void runcmd(struct cmd * cmd);

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

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

这是个递归的函数!

下面是来自github上的代码,仅摘录runcmd函数

 1 void
 2 runcmd(struct cmd *cmd)
 3 {
 4   int p[2]; // used for pipe line in shell
 5   int r;    // return value
 6   struct execcmd *ecmd;
 7   struct pipecmd *pcmd;
 8   struct redircmd *rcmd;
 9
10   if(cmd == 0)
11     exit(0);
12
13   switch(cmd->type){
14   default:
15     fprintf(stderr, "unknown runcmd\n");
16     exit(-1);
17
18   case ‘ ‘:
19     ecmd = (struct execcmd*)cmd;
20     if(ecmd->argv[0] == 0)
21       exit(0);
22     //fprintf(stderr, "exec not implemented\n");
23     // Your code here ...
24     if (access(ecmd->argv[0], S_IXUSR | S_IRUSR) == 0)
25     {
26         execv(ecmd->argv[0], ecmd->argv);
27     }
28     else
29     {
30         if(chdir("/bin/") < 0)
31         {
32             printf("change directory failed in line %d\n", __LINE__);
33             exit(0);
34         }
35         execv(ecmd->argv[0], ecmd->argv);
36     }
37     fprintf(stderr, "execv() %s failed in line %d\n", ecmd->argv[0], __LINE__);
38     break;
39
40   case ‘>‘:
41   case ‘<‘:
42     rcmd = (struct redircmd*)cmd;
43     //fprintf(stderr, "redir not implemented\n");
44     // Your code here ...
45     close(rcmd->fd);
46     if(open(rcmd->file, rcmd->mode) < 0)
47     {
48         fprintf(stderr, "Try to open :%s failed\n", rcmd->file);
49         exit(0);
50     }
51     runcmd(rcmd->cmd);
52     break;
53
54   case ‘|‘:
55     pcmd = (struct pipecmd*)cmd;
56     //fprintf(stderr, "pipe not implemented\n");
57     // Your code here ...
58     if(pipe(p) < 0)
59     {
60         fprintf(stderr, "call syscall pipe() failed in line %d\n", __LINE__);
61         exit(0);
62     }
63
64     if(fork1() == 0)
65     {
66         close(1);
67         dup(p[1]);
68         close(p[0]);
69         close(p[1]);
70         runcmd(pcmd->left);
71     }
72
73     if(fork1() == 0)
74     {
75         close(0);
76         dup(p[0]);
77         close(p[0]);
78         close(p[1]);
79         runcmd(pcmd->right);
80     }
81
82     close(p[0]);
83     close(p[1]);
84     wait();
85     wait();
86     break;
87   }
88
89   exit(0);
90 }

有兴趣可以点击查看详情

时间: 2024-12-21 02:11:26

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 ----------------------------------- 大家好,我是分割线 ------------------------------------------------------------------- 这

linux 输入输出流和文件描述符浅析

File descriptors 是一个整数 表内存管理的对象,该对象可以由进程进行读写. 一个进程可以获取File descriptors通过打开文件 目录 或者设备,通过创建管道 或者复制一个已经存在的descriptors, 文件描述符将文件 管道 设备都抽象化为一样的东西,都像字节流.文件描述符作为索引映射到 进程表中.每一个进程都有文件描述符的私有化控件,从0开始.进程读取文件 文件描述符为0 写入文件描述符为1 写错误信息到文件标识符为2. while((fd = open("con

MIT 6.828-operating system engineering homework: shell

这是6.828第一节的一个小作业,就是实现一个shell,大部分的源码都给了,但是编译一下发现很多bug和warning,所以需要读懂源代码然后自己改. 这次作业的重点在于理解和体会shell是怎么实现和构建的,尤其要体会的是unix系统中管道和重定向 关于shell实现的一些基本原理请看xv6-book chapter0A shell需要保证在任何时候都有三个打开的文件描述符,他们是控制台的默认文件描述符 惯例是从文件描述符0读入,从文件描述符1输出(标准输出),从文件描述符2输出错误 首先是

【Linux系列】【基础版】第四章 Shell基础之正则表达式

4. Shell基础之正则表达式     4.1 正则就是一串有规律的字符串         4.1 grep              4.1.1 格式: grep [-cinrvABC] 'word' filename             4.1.2 -c //count,表示行数             4.1.3 -i //不区分大小写             4.1.4 -n  //显示行号             4.1.5 -r  //遍历所有子目录             4

linux Shell函数

Shell函数类似于Shell脚本,里面存放了一系列的指令,不过Shell的函数存在于内存,而不是硬盘文件,所以速度很快,另外,Shell还能对函数进行预处理,所以函数的启动比脚本更快. 1.函数定义 1 2 3 4 function 函数名() {     语句     [return] } 关键字function表示定义一个函数,可以省略,其后是函数名,有时函数名后可以跟一个括号,符号"{"表示函数执行命令的入口,该符号也可以在函数名那一行,"}"表示函数体的结

Shell实现跳板机,为什么用跳板机

整理自:http://blog.chinaunix.net/uid-22101889-id-3167454.html 注意:请谨慎使用,到现在为止,使用了,我还没找到改回去的方法. 1.     问题 第一.很多大公司的服务器都不允许直接登录,而是通过一个跳板机才能登录过去.在跳板机中,通常只能执行几个少数命令(如SSH),而其他命令是不允许执行的,那么怎样才能实现这个功能呢? 第二.一些小公司,由于服务器比较少,不需要什么跳板机之类的说法,公司的开发运维人员加起来也就那么十几二十人,通常大家都

linux shell基础语法

1.第一个Shell脚本 打开文本编辑器,新建一个文件,扩展名为sh(sh代表shell),扩展名并不影响脚本执行,见名知意就好,如果你用php写shell 脚本,扩展名就用php好了. 输入一些代码: #!/bin/bash echo "Hello World !" "#!" 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种Shell.echo命令用于向窗口输出文本. 运行Shell脚本有两种方法. 1.1作为可执行程序 将上面的代码保存为t

shell中test命令方法详解

test命令用法.功能:检查文件和比较值 1)判断表达式 if test  (表达式为真) if test !表达式为假 test 表达式1 –a 表达式2                  两个表达式都为真 test 表达式1 –o 表达式2                 两个表达式有一个为真 2)判断字符串 test –n 字符串                                   字符串的长度非零 test –z 字符串                          

shell脚本

-e filename 如果 filename存在,则为真 [ -e /var/log/syslog ]-d filename 如果 filename为目录,则为真 [ -d /tmp/mydir ]-r filename 如果 filename可读,则为真 [ -r /var/log/syslog ]-w filename 如果 filename可写,则为真 [ -w /var/mytmp.txt ]-x filename 如果 filename可执行,则为真 [ -L /usr/bin/gr

20.5 Shell脚本中的逻辑判断;20.6 文件目录属性判断;20.7 if特殊用法;20.8 20.9 cace判断(上下)

扩展: select用法 http://www.apelearn.com/bbs/thread-7950-1-1.html 20.5 Shell脚本中的逻辑判断 格式1:if 条件 ; then 语句; fi 1. 创建if1.sh测试脚本: [[email protected] ~]# vi if1.sh a=5,如果a大于3,满足这个条件,显示ok 添加内容: #!/bin/bash a=5 if [ $a -gt 3 ] then echo ok fi 2. 执行if1.sh脚本: [[e