MIT-6.s081-OS lab sh : Simple xv6 shell

实验说明:https://pdos.csail.mit.edu/6.828/2019/labs/sh.html

离上次做完实验一快有二十多天了 期间不是不想做这个实验 主要是两个困难:

1.不会使用gdb

2. 要从头实现一个shell,并且要处理

grep lion < data.txt | wc > count

这种看起来很复杂的命令,我被吓住了,因为传说中的AST我不会,而有些博客写的用字符串处理的方式因为比较个性化我又看不懂,所以觉得很难,做起来很难受,不过总的来说,这二十多天里,大部分时间我不是在解决问题,而是在逃避问题

总算这一周有了突破,除了实验上,更多是心理上和认知上:心理上主要就是增强自信了(指实现突破后

认知上的突破在于:不要一开始就看着最难的东西 从小处入手 其实这个实验本来也是这么设计的

比如评分标准里首先是simple echo,单纯实现这个的话还是挺简单的,只需要设置一下exec的参数即可(把命令行的指令split一下,当然c语言没有split,所以write from scratch确实有些难度)

然后比较简单的是simple io redirection,simple pipe,之所以是simple,指的是这种指令:

echo hello > file

wc < file

cat file | wc

很直接 只含有三者其一 所以判断一下 就可以写出相应的代码

比较让人觉得难的是both redirection,pipe and redirect

就是本文一开始提到的那种 不熟的话看起来会觉得很难处理 不过也可以start small:即给出一个具体的例子 思考应该怎么处理

比如:

grep lion < data.txt | wc > count

我们首先根据 | 的位置 ,把命令行的输入分开,因为他的两边都是指令,需要fork-exec

然后利用一点类似递归的技巧,就可以完成,至少可以通过测试了~

// 先贴代码吧 改天再总结

#include "kernel/types.h"
#include "user/user.h"
#include "kernel/fcntl.h"

void execPipe(char*argv[],int argc);
//*****************START  from sh.c *******************


#define MAXARGS 10
#define MAXWORD 30
#define MAXLINE 100

int getcmd(char *buf, int nbuf)
{
    fprintf(2, "@ ");
    memset(buf, 0, nbuf);
    gets(buf, nbuf);
    if (buf[0] == 0) // EOF
        return -1;
    return 0;
}
char whitespace[] = " \t\r\n\v";
char args[MAXARGS][MAXWORD];

//*****************END  from sh.c ******************
void setargs(char *cmd, char* argv[],int* argc)
{
    // 让argv的每一个元素都指向args的每一行
    for(int i=0;i<MAXARGS;i++){
        argv[i]=&args[i][0];
    }
    int i = 0; // 表示第i个word
    // int k = 0; // 表示word中第k个char
    int j = 0;
    for (; cmd[j] != '\n' && cmd[j] != '\0'; j++)
    {
        // 跳过之前的空格
        while (strchr(whitespace,cmd[j])){
            j++;
        }
        argv[i++]=cmd+j;
        // 只要不是空格,就j++,找到下一个空格
        while (strchr(whitespace,cmd[j])==0){
            j++;
        }
        cmd[j]='\0';
    }
    argv[i]=0;
    *argc=i;
}

// void runcmd(char *cmd)
void runcmd(char*argv[],int argc)
{
    for(int i=1;i<argc;i++){
        if(!strcmp(argv[i],"|")){
            // 如果遇到 | 即pipe,至少说明后面还有一个命令要执行
            execPipe(argv,argc);
        }
    }
    // 此时是仅处理一个命令:现在判断argv[1]开始,后面有没有> 
    for(int i=1;i<argc;i++){
        // 如果遇到 > ,说明需要执行输出重定向,首先需要关闭stdout
        if(!strcmp(argv[i],">")){
            close(1);
            // 此时需要把输出重定向到后面给出的文件名对应的文件里
            // 当然如果>是最后一个,那就会error,不过暂时先不考虑
            open(argv[i+1],O_CREATE|O_WRONLY);
            argv[i]=0;
            // break;
        }
        if(!strcmp(argv[i],"<")){
            // 如果遇到< ,需要执行输入重定向,关闭stdin
            close(0);
            open(argv[i+1],O_RDONLY);
            argv[i]=0;
            // break;
        }
    }
    exec(argv[0], argv);
}

void execPipe(char*argv[],int argc){
    int i=0;
    // 首先找到命令中的"|",然后把他换成'\0'
    for(;i<argc;i++){
        if(!strcmp(argv[i],"|")){
            argv[i]=0;
            break;
        }
    }
    // 先考虑最简单的情况:cat file | wc
    int fd[2];
    pipe(fd);
    if(fork()==0){
        // 子进程 执行左边的命令 把自己的标准输出关闭
        close(1);
        dup(fd[1]);
        close(fd[0]);
        close(fd[1]);
        // exec(argv[0],argv);
        runcmd(argv,i);
    }else{
        // 父进程 执行右边的命令 把自己的标准输入关闭
        close(0);
        dup(fd[0]);
        close(fd[0]);
        close(fd[1]);
        // exec(argv[i+1],argv+i+1);
        runcmd(argv+i+1,argc-i-1);
    }
}
int main()
{
    char buf[MAXLINE];
    // Read and run input commands.
    while (getcmd(buf, sizeof(buf)) >= 0)
    {

        if (fork() == 0)
        {
            char* argv[MAXARGS];
            int argc=-1;
            setargs(buf, argv,&argc);
            runcmd(argv,argc);
        }
        wait(0);
    }

    exit(0);
}

然后评分:

red@red-vm-ubuntu:~/6s081/xv6-riscv-fall19$ ./grade-lab-sh
make: 'kernel/kernel' is up to date.
running nsh tests: (4.6s) 
  simple echo: OK 
  simple grep: OK 
  two commands: OK 
  output redirection: OK 
  input redirection: OK 
  both redirections: OK 
  simple pipe: OK 
  pipe and redirects: OK 
  lots of commands: OK 
Score: 100/100

猜你喜欢

转载自blog.csdn.net/RedemptionC/article/details/106962836