MIT6.828 | Hw-3: Shell 【待填坑】

LINK

这节课主要通过完善给出的代码实现简单的 shell

Read Chapter 0 of the xv6 book.

下载代码:wget https://pdos.csail.mit.edu/6.828/2018/homework/sh.c

创建包含以下命令的 t.sh 文件

1
2
3
4
5
6
ls > y
cat < y | sort | uniq | wc > y1
cat y1
rm y1
ls |  sort | uniq | wc
rm y 

编译 sh.c: gcc sh.c 生成 a.out

运行脚本:./a.out < t.sh

1
2
3
4
5
6
7
redir not implemented 
exec not implemented 
pipe not implemented 
exec not implemented 
exec not implemented 
pipe not implemented
exec not implemented

接下来是 shell 命令的实现。

1. Executing simple commands

实现简单的命令 ls,能够列出当前目录的文件。

终端键入man 3 exec, 查看手册,可以看到如下:

The execv(), execvp(), and execvpe() functions provide an array of pointers to null-terminated strings that represent the argument list available to the new program.  The first argument, by convention, should point to the filename associated with the file being executed. The array of pointers must be terminated by a null pointer.

具体实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
  case ' ':
    ecmd = (struct execcmd*)cmd;
    if(ecmd->argv[0] == 0)
      _exit(0);
    // fprintf(stderr, "exec not implemented\n");    
    // Your code here ...
    if (!access(ecmd->argv[0], F_OK))   //cmd exists in current directory
      execv(ecmd->argv[0], ecmd->argv);
    else {  //cmd exists in current directory, run /bin/<cmd>
      strcpy(path, root);         // path = "/bin/"
      strcat(path, ecmd->argv[0]);// path = "/bin/<cmd>"
      if(!access(path, F_OK))
            execv(path, ecmd->argv);
        else
           fprintf(stderr, "Command <%s> not found.\n", ecmd->argv[0]);
    }
    break;

重新编译后运行:

6.828$ ls 
'MIT6.828 Hw-3 Shell.md'   a.out   sh.c   t.sh   tmp 

2. I/O redirection

实现重定向:

1
2
echo "6.828 is cool" > x.txt
cat < x.txt

添加重定向命令代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  case '>':
  case '<':
    rcmd = (struct redircmd*)cmd;
    // fprintf(stderr, "redir not implemented\n");
    // Your code here ...
    close(rcmd->fd);  // close stdin or stdout, which is the default I/O
    // open file with fd 0(write) or 1(read)
    if(open(rcmd->file, rcmd->flags, 0777) < 0) {
      fprintf(stderr, "open %s failed!\n", rcmd->file);
      exit(0);
    }
    runcmd(rcmd->cmd);
    break;

重新编译并运行:

1
2
3
6.828$ echo "6.828 is cool" > x.txt 
6.828$ cat < x.txt 
"6.828 is cool" 

3. Implement pipes

Reference:

参考课本上第13页 pipe 的代码,实现如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
case '|':
    pcmd = (struct pipecmd*)cmd;
    // fprintf(stderr, "pipe not implemented\n");
    // Your code here ...
    if (pipe(p) == -1) {
      fprintf(stderr, "create pipe failed!\n");
      exit(0);
    }
    // using pipe(p) to create a new pipe
    // and record the read and write file descriptor in the array p
    if(fork() == 0) {
      dup2(p[1], STDOUT_FILENO);  // redirect stdout to p[1] (read end of pipe)
      close(p[0]);  // close stdin cloned by fork
      close(p[1]);  // close stdout cloned by fork
      runcmd(pcmd->left);         // child process for left cmd
    }
    if(fork() == 0) {
      dup2(p[0], STDIN_FILENO);   // redirect stdin to p[0] (out end of pipe)
      close(p[0]);  // close stdin cloned by fork
      close(p[1]);  // close stdout cloned by fork
      runcmd(pcmd->right);        // child process for right cmd
    }
    close(p[0]);
    close(p[1]);
    wait(&r);
    wait(&r);
    break;  
  }    
  _exit(0);

重新编译后运行:

1
2
3
4
5
6
7
6.828$ ls | sort 
MIT6.828 Hw-3 Shell.md 
a.out
sh.c
t.sh
tmp
x.txt

4. Optional challenge exercises【待填坑】

The following exercises are entirely optional and won't affect your grade. Add any feature of your choice to your shell, for example:

  • Implement lists of commands, separated by ";"
  • Implement sub shells by implementing "(" and ")"
  • Implement running commands in the background by supporting "&" and "wait"

All of these require making changes to the parser and the runcmd function.

updatedupdated2023-01-302023-01-30
点击刷新