OSwork_Shell实验报告

xv6 Shell实验报告

实验任务:◀️Homework: shell (mit.edu)

1. Executing simple commands 执行简单命令

2. I/O redirection I/O 重定向

3. Implement pipes 实现管道

前言

定义命令类型 cmd为抽象类,execcmd为exec cmd,redircmd 为redirect(重定向) cmd,pipcmd 为 pipe(管道) cmd

struct cmd {
  int type;          //  ' ' (exec), | (pipe), '<' or '>' for redirection
};

struct execcmd {
  int type;              // ' '
  char *argv[MAXARGS];   // arguments to the command to be exec-ed
};

struct redircmd {
  int type;          // < or > 
  struct cmd *cmd;   // the command to be run (e.g., an execcmd)
  char *file;        // the input/output file
  int mode;          // the mode to open the file with
  int fd;            // the file descriptor number to use for the file
};

struct pipecmd {
  int type;          // |
  struct cmd *left;  // left side of pipe
  struct cmd *right; // right side of pipe
};

命令执行器 runcmd 为代码实现部位

void runcmd(struct cmd *cmd)

任务

执行简单命令

case ' ':
    ecmd = (struct execcmd*)cmd;
    if(ecmd->argv[0] == 0)
      exit(0);
    execvp(ecmd->argv[0], ecmd->argv);
    fprintf(stderr, "exec not implemented\n");
    // Your code here ...

    break;

注意到这是普通命令类 execcmd

调用exec()执行命令

使用execvp可以调用环境变量

Reason:

系统命令在 \bin\\usr\bin 目录下,如果使用execv的话要给出完整的目录

This prints a prompt and waits for input. sh.c prints as prompt 6.828$ so that you don’t get confused with your computer’s shell. Now type to your shell:

6.828$ ls

Your shell may print an error message (unless there is a program named ls in your working directory or you are using a version of exec that searches PATH). Now type to your shell:

6.828$ /bin/ls

This should execute the program /bin/ls, which should print out the file names in your working directory. You can stop the 6.828 shell by typing ctrl-d, which should put you back in your computer’s shell.

exec函数没有返回,错误才返回⬇️​

本地可执行程序

发现无法运行本地可执行文件,so➡️

char mypath[20]="./";
    if(execvp(ecmd->argv[0], ecmd->argv)==-1){// 判断
      strcat(mypath, ecmd->argv[0]);// 合成,注意是ecmd->argv[0]
      execv(mypath, ecmd->argv);// 执行
    }

对原代码做出调整,将路径添加到execv,ecmd->argv是 ** 类型!

tip:

execv 与 execl 互斥

l表示该函数取一个参数表,它与字母v互斥。

v表示该函数取一个argv [ ]矢量。

重定向

重定向输入输出

 case '>':
 case '<':
	rcmd = (struct redircmd *)cmd;
    // 打开文件进行输入/输出重定向
    int file_fd = open(rcmd->file, rcmd->mode, 0666);
    if (file_fd == -1) {
    perror("open");
    exit(EXIT_FAILURE);
    }

    // 关闭文件描述符 rcmd->fd
    close(rcmd->fd);

    // 将新打开的文件描述符与 rcmd->fd 关联
    if (dup2(file_fd, rcmd->fd) == -1) {
        perror("dup2");
        exit(EXIT_FAILURE);
    }

    // 关闭不再需要的文件描述符
    close(file_fd);

    // 递归执行重定向后的命令
    runcmd(rcmd->cmd);
    break;

通过文件描述符控制输入输出,注意关闭其他输入输出文件描述符

使用dup2进行重定向

在shell的重定向功能中,(输入重定向”<”和输出重定向”>”)就是通过调用dup或dup2函数对标准输入和标准输出的操作来实现的

实现管道

  case '|':
    pcmd = (struct pipecmd*)cmd;
    // Your code here ...
    if(pipe(p) < 0)
    {
      fprintf(stderr,"Fail to create a pipe\n");
	    exit(0);
    }
    if(fork1() == 0){
      close(1);
      dup(p[1]);
      close(p[0]);
      close(p[1]);
      runcmd(pcmd->left);
    }
    else{
      close(0);
      dup(p[0]);
      close(p[0]);
      close(p[1]);
      runcmd(pcmd->right);
    }
    close(p[0]);
    close(p[1]);

    wait(&r);

    break;

pipe(p)管道创建p[0]读、p[1]写

dup()重定向

fork创建管道的子进程,把整个命令看做一个管道命令由管道可分出左右两个命令,再由runcmd自调用实现递归

注意一下wait函数的使用,因为管道是有顺序的,所以父进程是不能放任的。
正如递归父级调用需要等待子级return才能继续执行。

❗️❗️Warning:

在开始我将左右两个命令视为同级,就创建了两个子进程。也就使用两个if,然而这将会导致重复*(父进程被复制了两遍!!*

if(fork1() == 0){
close(1);
dup(p[1]);
close(p[0]);
close(p[1]);
runcmd(pcmd->left);
}
if(fork1() == 0){
close(0);
dup(p[0]);
close(p[0]);
close(p[1]);
runcmd(pcmd->right);
}

应采用父进子出,或子进父出—> if… else…

总结

了解了linux的系统调用,通过抽象本质进行分类封装,从而使代码十分精简。

所有命令类型的子命令都采用了cmd类型,但实际可能是任何一种具体的命令类型。相当于在c语言里使用了类似面向对象的继承与多态的性质,所有的命令类型都继承自一个基础的结构体cmd。它们在实际命令执行的时候再根据type参数向下转型为真正的命令类型。这种技巧使代码变得非常简洁,命令的构造变得统一,构造命令时无需知道子命令是什么,便于递归构造命令串。

其他http://t.csdnimg.cn/PG4YL

参考

MIT6.828学习之homework2:shell;

xv6 shell实现源代码分析;

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值