xv6 6.S081 Lab2: shell

xv6 6.S081 Lab2: shell

Shell代码在这里。

写在前面

echo a > file
grep deadpool < deadpoolStory.txt | echo > file

上述命令展示了Linux中的重定向与管道机制。
其中,
重定向是将标准输入或输出重定向至一个文件描述符内,例如:echo a > file,echo命令本来是将内容写入标准输出,然后展示到Shell上,但是这里有一个重定向符">",它将echo的标准输出定向到了文件的输入中,因此该命令是向文件file中写入字符a。
管道机制是将管道左侧的标准输出作为管道右侧的标准输入,在上述例子中,grep deadpool < deadpoolStory.txt首先通过grep将deadpoolStory.txt中的“deadpool”写入标准输出,但是管道将标准输出变成了右侧管道的标准输入,即:echo将这些grep到的deadpool都写入了文件file中。

事实上,不管是重定向还是管道,都是衍生出来的概念,为了不把脑子搅得一团乱麻,可以这么来理解:Linux中的标准输入、标准输出亦或是标准错误输出都是文件,它们各持有一个独特的文件描述符:0、1、2。重定向或者管道就是在文件间倒来倒去。例如echo a > file,echo a本来是将a写入标准输出1中,但是由于">",echo a将a写入了文件file中;而grep deadpool < deadpoolStory.txt | echo > file中|之前的命令本来要写入标准输出1中,但是由于"|",它写入了标准输入0中,而echo进程读取的正是0中的内容,因此就把左边命令的标准输出读了进来,这里本来应该将左边命令的标准输出写入标准输出1中,但是又碰到了">",于是就把内容写入了文件file中。个人认为,把各种标准输入输出都理解为对文件的操作(本来就是如此),会对管道亦或是重定向理解得更加透彻。

实验介绍

本实验要求完成一个简单的Shell,这里是官方指导书

开始!

在这里插入图片描述
官方给了一大堆Hints,这里我挑重点说一下:
1、不能使用malloc
2、可以参考sh.c
3、不用实现没有要求的命令
4、运行testsh.c可以帮助测试

本实验的难点在于不准使用malloc,而sh.c中全是用malloc实现的。那么如何解析命令并将其存储呢?其实方法很简单,声明一个静态数组就好了。下面给出代码

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

#define MAXBUFSIZ 256 
#define MAXSTACKSIZ 100 
#define MAXARGS 10
#define ECHO "echo"
#define GREP "grep"
#define CAT "cat"   
/* Not allowed to use _MLOC*/

/********************** definition *************************/
char whitespace[] = " \t\r\n\v";
char symbols[] = "<|>&;()";



typedef enum CmdType
{
  Execcmd,
  Redircmd,
  Pipecmd,
  NULLcmd
} cmdtype;

typedef enum RedirType
{
  Stdout2file,
  File2stdin
} redirtype;

typedef enum Boolean
{
  false,
  true
} boolean;


typedef struct cmd
{
  /* data */
  cmdtype type;
  union cmdcontent
  {
    struct pipecmd 
    {
      /* data */
      struct cmd* leftcmd;
      struct cmd* rightcmd;
    } pipecmd;

    struct redircmd
    {
      /* data */
      struct cmd* stdincmd;
      struct cmd* stdoutcmd;
      redirtype redirtype;  // <: file2stdin 或者 >: stdout2file 
      int fd; //相关的IO描述符
      char *file; //文件名
      int mode; //打开文件方式
    } redircmd;

    struct execcmd {
      char *argv[MAXARGS];
    } execcmd;

  } cmdcontent;
} cmd;


cmd cmdstack[MAXSTACKSIZ];     //用于给cmd分配空间,保存递归cmd
char tokens[MAXARGS][MAXPATH]; //用于保存execcmd的参数
char files[MAXARGS][MAXPATH];  //用于保存redircmd文件名
/**************************** headerfunction ***********************/
cmd* parsecmd(char *cmd, char *_endofcmd,int currentstackpointer);


/************************* utils ************************/
/* borrow from sh.c line 310 */
void init(); //清空cmdstack以及tokens
int gettoken(char **ps, char *es,int startpos, char **token, char **endoftoken); //利用空格切分Token
void parsetoken(char **token, char *endoftoken, char *parsedtoken);
int allocatestack();
int allocatetokens();
int allocatefiles();
/* do with cmd */
void evaluate(cmd* parsedcmd);
void preprocessCmd(char *cmd);

/*************************** code_implements *************************/

cmd nullcmd;

int 
main() { 
  char _cmd[MAXBUFSIZ];
  nullcmd.type = NULLcmd;
  while (true)
  {
      /* code */
      memset(_cmd, 0, sizeof(_cmd));
      printf("@ ");
      gets(_cmd, MAXBUFSIZ);
      preprocessCmd(_cmd);
      /* important */
      if(strlen(_cmd) == 0 || _cmd[0] == 0){
          exit(0);
      }
      //printf("_cmd: %s\n", _cmd);
      /* parse cmd */
      init();
      char *endofcmd;
      endofcmd = _cmd + strlen(_cmd);
      cmd* parsedcmd = parsecmd(_cmd, endofcmd, 0);
      /* start run */
      if(fork() == 0)
        evaluate(parsedcmd);
      wait(0);
  }
  return 0;
}

/******************* 处理cmd ******************/
void 
evaluate(cmd *parsedcmd){
  int pd[2];

  if(parsedcmd->type == NULLcmd){
    return ;
  }
  
  switch (parsedcmd->type)
  { 
  /* code */
  case Pipecmd:
    /* fprintf(2,"-------------exec pipecmd-------------: \n");
    fprintf(2,"pipe left cmd type: %d\n", parsedcmd->cmdcontent.pipecmd.leftcmd->type);
    fprintf(2,"pipe right cmd type: %d\n", parsedcmd->cmdcontent.pipecmd.rightcmd->type); */
    /* stdout | stdin */
    //parsedcmd.cmdcontent.pipecmd;
    pipe(pd);
    /* stdout */
    /* 左边命令的输出将会定位到标准输出内 */
    /* Child */
    if(fork() == 0){
      close(1);
      dup(pd[1]);
      close(pd[0]);
      close(pd[1]);
      //fprintf(2,"arrived at left\n");
      evaluate(parsedcmd->cmdcontent.pipecmd.leftcmd);
    }
    /* stdin */
    /* 右边命令的输入将被重定向到标准输入内 */
    /* Parent */
    else {
      close(0);
      dup(pd[0]);
      close(pd[0]);
      close(pd[1]);
      evaluate(parsedcmd->cmdcontent.pipecmd.rightcmd);
    }
    wait(0);
    /* stdin */
    break;

  case Execcmd:
    /* fprintf(2,"exec execmd: %s, %d\n",parsedcmd->cmdcontent.execcmd.argv[0], strlen(parsedcmd->cmdcontent.execcmd.argv[0])); */
    exec(parsedcmd->cmdcontent.execcmd.argv[0], parsedcmd->cmdcontent.execcmd.argv);
    break;
  
  case Redircmd:
    /* cat < d */
    /* < 0, > 1 */
    /* fprintf(2, "exec redircmd: \n");
    fprintf(2, "file name:%s\n", parsedcmd->cmdcontent.redircmd.file);
    fprintf(2, "stdin cmd:%s \n", parsedcmd->cmdcontent.redircmd.stdincmd->cmdcontent.execcmd.argv[0]);
    fprintf(2, "stdout cmd:%s\n", parsedcmd->cmdcontent.redircmd.stdoutcmd->cmdcontent.execcmd.argv[0]);;
    fprintf(2, "stdout cmd type:%d\n", parsedcmd->cmdcontent.redircmd.stdoutcmd->type);
    fprintf(2, "fd:%d\n", parsedcmd->cmdcontent.redircmd.fd);  */

    close(parsedcmd->cmdcontent.redircmd.fd);
    if(open(parsedcmd->cmdcontent.redircmd.file, parsedcmd->cmdcontent.redircmd.mode) < 0){
      fprintf(2, "open %s failed\n", parsedcmd->cmdcontent.redircmd.file);
      exit(-1);
    }
    if(parsedcmd->cmdcontent.redircmd.redirtype == File2stdin){
      evaluate(parsedcmd->cmdcontent.redircmd.stdincmd);
    }
    else if(parsedcmd->cmdcontent.redircmd.redirtype == Stdout2file)
    {
      evaluate(parsedcmd->cmdcontent.redircmd.stdoutcmd);
    }
    break;
  default:
    break;
  }
  
}

/* | > < */
/* 管道|具有最高优先级 */
cmd* 
parsecmd(char *_cmd, char *_endofcmd, int currentstackpointer){
  char *s;
  s = _endofcmd;
  //printf("--------------------parsecmd--------------------\n");
  boolean isexec = true;
  boolean ispipe = false;
  /* 先找管道 */
  for(; s >= _cmd; s--){
    if (*s == '|')
    {
      cmdstack[currentstackpointer].type = Pipecmd;
      cmdstack[currentstackpointer].cmdcontent.pipecmd.leftcmd = parsecmd(_cmd, s - 1, allocatestack());
      cmdstack[currentstackpointer].cmdcontent.pipecmd.rightcmd = parsecmd(s + 1, _endofcmd, allocatestack());
      isexec = false;
      ispipe = true;
      break;
    }
  }
  /* 再找重定向符 */
  if(!ispipe){
    s = _endofcmd;
    for (; s >= _cmd; s--)
    {
      /* code */
      if (*s == '<' || *s == '>')
      {
        cmdstack[currentstackpointer].type = Redircmd;
        /* code */
        /* stdin < file */
        if(*s == '<'){
          cmdstack[currentstackpointer].cmdcontent.redircmd.redirtype = File2stdin;
          cmdstack[currentstackpointer].cmdcontent.redircmd.fd = 0;
          cmdstack[currentstackpointer].cmdcontent.redircmd.stdincmd = parsecmd(_cmd, s - 1, allocatestack());
          cmdstack[currentstackpointer].cmdcontent.redircmd.stdoutcmd = &nullcmd;
          cmdstack[currentstackpointer].cmdcontent.redircmd.mode = O_RDONLY;
        }
        /* stdout > file */
        else {
          cmdstack[currentstackpointer].cmdcontent.redircmd.redirtype = Stdout2file;
          cmdstack[currentstackpointer].cmdcontent.redircmd.fd = 1;
          cmdstack[currentstackpointer].cmdcontent.redircmd.stdincmd = &nullcmd;
          cmdstack[currentstackpointer].cmdcontent.redircmd.stdoutcmd = parsecmd(_cmd, s - 1, allocatestack());
          cmdstack[currentstackpointer].cmdcontent.redircmd.mode = O_WRONLY|O_CREATE;
        }
        char *file, *endoffile;
        gettoken(&_cmd, _endofcmd,  s - _cmd + 1, &file, &endoffile);
        int pos = allocatefiles();
        parsetoken(&file, endoffile, files[pos]);
        cmdstack[currentstackpointer].cmdcontent.redircmd.file = files[pos]; 
        isexec = false;
        break;
      }
    }
    if(isexec){
      cmdstack[currentstackpointer].type = Execcmd;
      int totallen = _endofcmd - _cmd;
      int startpos = 0;
      int count = 0;
      while (startpos < totallen)
      {
        /* code */
        char *token, *endoftoken;
        startpos = gettoken(&_cmd, _endofcmd, startpos, &token, &endoftoken);
        if(*token != ' '){
          //printf("token addr: %p\n", token);
          int pos = allocatetokens();
          parsetoken(&token, endoftoken, tokens[pos]);
          //printf("token: %s, %d\n", tokens[pos], strlen(tokens[pos]));
          cmdstack[currentstackpointer].cmdcontent.execcmd.argv[count] = tokens[pos];
          count++;
        }
      }
      cmdstack[currentstackpointer].cmdcontent.execcmd.argv[count] = 0;
    }
  }
  return &cmdstack[currentstackpointer];
}

void 
init(){
  memset(tokens, 0, sizeof(tokens));
  memset(files, 0, sizeof(files));
  memset(cmdstack, 0, sizeof(cmdstack));
  for (int i = 0; i < MAXSTACKSIZ; i++)
  {
    /* code */
    cmdstack[i].type = NULLcmd;
  }
}
/* 分配栈 */
int
allocatestack(){
  int newpointer = 0;
  while(cmdstack[newpointer].type != NULLcmd) newpointer++;
  return newpointer;
}

int
allocatetokens(){
  int newpointer = 0;
  while(tokens[newpointer][0] != 0) newpointer++;
  return newpointer;
}

int
allocatefiles(){
  int newpointer = 0;
  while(files[newpointer][0] != 0) newpointer++;
  return newpointer;
}

/* 去掉回车符 */
void
preprocessCmd(char *cmd){
  int n = strlen(cmd);
  if(n > MAXBUFSIZ){
      printf("command too long!");
      exit(0);
  }
  else
  {
      /* code */
      if(cmd[n - 1] == '\n'){
          cmd[n - 1] = '\0';
      }
  }
}

/************************* Utils **************************/
void parsetoken(char **token, char *endoftoken, char *parsedtoken){
  //printf("gettoken: ");
  char *s = *token;
  for (; s < endoftoken; s++)
  {
    *(parsedtoken++) = *s;
    //printf("%c", *s);
  }
  *parsedtoken = '\0';
  //printf("\n");
}

int
gettoken(char **ps, char *es, int startpos, char **token, char **endoftoken)
{
  char *s;
  int pos = startpos;
  s = *ps + startpos;
  /* 清理所有s的空格 trim */
  while(s < es && strchr(whitespace, *s)){
    s++;
    pos++;
  }
  *token = s;
  while (s < es && !strchr(whitespace, *s))
  {
    /* code */
    s++;
    pos++;
  }
  *endoftoken = s;
  return pos;
}  
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值