MIT Operating System - 2 - hw2:shell

hw2:shell

fork() 会产生两个进程,之后,就通过返回值的不同,区分两个值

wait() 返回子进程的pid,如果没有,等待子进程的产生

exec(a,b) 执行可执行文件,替换掉内存,但文件描述符不变
exec(a,b,c) 表明文件读写权限

文件描述符

0 stdin
1 stdout
2 stderr

shell要保证三个文件描述符处于打开状态
read(fd, buf, n)
从文件描述符fd读取最多n个bytes,放入到buf,返回读取byte数目
fd保存着一个offset,维护读的位置

write(fd, buf, n)
把buff中的n个buf写入fd

close 释放文件描述符
dup 复制一个文件描述符,但是共享offset

作业

这次的作业是要实现一个shell,完成基本的命令行命令,实现起来比较简单,需要提前理解文件描述符的使用方法,以及exec,open,pipe等系统调用的使用方法及参数的意义

part1:实现普通命令

case ' ':
    ecmd = (struct execcmd*)cmd;
    if(ecmd->argv[0] == 0)
      _exit(0);
    //fprintf(stderr, "exec not implemented\n");
    if (execv(ecmd->argv[0], ecmd->argv) == -1)         //先在当前目录下搜索执行文件
    { //argv[0]代表路径,这里仅仅是命令,argv是命令+命令参数
                char cmdPath[30] = "/bin/";
                strcat(cmdPath, ecmd -> argv[0]);
                fprintf(stderr, "the path is %s\n", cmdPath);
                if(execv(cmdPath, ecmd->argv) == -1)    //以上执行失败,在/bin/目录下搜索执行文件
                {
                   char cmdPath2[30] = "/usr/bin/";
                   strcat(cmdPath2, ecmd -> argv[0]);
                   if(execv(cmdPath2, ecmd->argv) == -1)        //以上执行失败,在/usr/bin/目录下搜索执行文件
                   {
                           fprintf(stderr, "Command %s not found %d\n", ecmd -> argv[0], __LINE__);     //都失败,执行文件不存在,结束当前进程
                           exit(0);
                   }
                }
    }
    break;

实现思路比较简单,执行execv系统调用,首先在当前目录下尝试执行,如果不成功,会尝试在两个/bin目录下执行,还执行不成功就报错

part2 实现输入输出重定向

case '>':
case '<':

    rcmd = (struct redircmd*)cmd;
    //fprintf(stderr, "redir not implemented\n");
    close(rcmd->fd);    //close stdin or stdout
    if(open(rcmd->file, rcmd->flags, 0777) < 0) {       //open file with fd 0(stdin) or 1(stdout)
        fprintf(stderr, "open %s failed!\n", rcmd->file);
        exit(0);
    }
    // Your code here ...
    runcmd(rcmd->cmd);
    break;

关闭当前文件,打开重定向的输入或输出的文件,0777代表拥有者,同组用户,其余用户可读、写、执行,啥都能干呗,想peach得peach呗

part2 实现管道

case '|':
    pcmd = (struct pipecmd*)cmd;
    //fprintf(stderr, "pipe not implemented\n");
    // Your code here ...
    int r;
    if(pipe(p) < 0)
    {
        fprintf(stderr, "call syscall pipe() failed in line %d\n", __LINE__);
        exit(0);
    }

    if(fork1() == 0)                                    //pipe的产生
    {
        close(1);
        dup(p[1]);                                      // 标准输出被赋予fd:p[1]
        close(p[0]);
        close(p[1]);                                    // 这样fd表里只剩下标准输入fd:0 和输出fd:p[1]
        runcmd(pcmd->left);
    }

    if(fork1() == 0)
    {
        close(0);
        dup(p[0]);                                      // 标准输入被赋予fd:p[0]
        close(p[0]);
        close(p[1]);                                    // 这样fd表里只剩下标准输出fd:1 和 输入fd:p[0]
        runcmd(pcmd->right);
    }

    close(p[0]);
    close(p[1]);
    wait(&r);
    wait(&r);
    break;

这一个需要一点点pipe系统调用和文件描述符的知识
我们知道,一个程序它自己是不知道从哪里获取输入,输出的,Linux把所有程序的输入输出抽象为文件描述符这一概念,每一个进程可以维护一个文件描述符表,表里面存储着打开的文件,程序通过这个表识别自己要向哪里输出,从哪里获得输入,shell进程在运行时,会时时刻刻检查至少三个文件描述符处于打开状态,默认0时系统输入,1时系统输出,2时错误输出
而我们想要实现的重定向,就是把上述文件描述符替换为我们想要的文件
代码中,pipe()系统待用会产生两个文件描述符放到p中(分别代表此管道的输入和输出,之后,我们为管道两边的进程都创建子进程,同时分别把其中一个替换为p中的一个,通过这种方法,我们就成功地把内容重定向到了我想要的文件中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值