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=(structexeccmd*)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);elsefprintf(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=(structredircmd*)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"
case'|':pcmd=(structpipecmd*)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);