HW2 Shell
6.828的shell主要有两个功能,一个是解析shell命令,一个是执行它们。6.828可以识别普通命令,重定向和pipe管道等。
1.普通exec命令的实现
在case’ '中直接实现即可,根据提示用到了unistd.h头文件中的execv方法
根据man 3 exec显示的提示可以看到:execv的第一个参数是路径,第二个参数是一个数组。根据详细描述可以知道,execv的第一个参数是和文件路径相联系的,所以我们可以简单地写出应用逻辑如下:
//exec
case ' ':
ecmd = (struct execcmd*)cmd;
if(ecmd->argv[0] == 0)
_exit(0);
//fprintf(stderr, "exec not implemented\n");
// Your code here ...
execv(ecmd->argv[0], ecmd->argv);
break;
但这样写出的代码只能在/bin目录下运行,
要使ls能够直接成功运行,需要借助另外的几个函数。
/ pathname :文件路径
// mode : 操作模式
int access(const char * pathname, int mode)
R_OK 测试读许可权
W_OK 测试写许可权
X_OK 测试执行许可权
F_OK 测试文件是否存在
access函数用来测试文件是否存在,strcpy函数用来复制字符串,strcat函数用来连接字符串。
当我们输入/bin/ls时,ecmd->argv[0]的值为/bin/ls,而此时我们要做的是当输入ls时,execv的第一个参数仍然为/bin/ls此时就要用到strcat函数,将/bin/与ls连接起来。代码如下;
执行结果如下图:
2.重定向的实现
实现重定向主要用到了open函数,该函数的定义如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
open函数的返回值如果操作成功,它将返回一个文件描述符,如果操作失败,它将返回-1。
参数简介:见博客https://blog.csdn.net/ArchyLi/article/details/78937937。
Linux访问模式,十进制表示:
-rw------- (600) 只有拥有者有读写权限。
-rw-r--r-- (644) 只有拥有者有读写权限;而属组用户和其他用户只有读权限。
-rwx------ (700) 只有拥有者有读、写、执行权限。
-rwxr-xr-x (755) 拥有者有读、写、执行权限;而属组用户和其他用户只有读、执行权限。
-rwx--x--x (711) 拥有者有读、写、执行权限;而属组用户和其他用户只有执行权限。
-rw-rw-rw- (666) 所有用户都有文件读、写权限。
-rwxrwxrwx (777) 所有用户都有读、写、执行权限。
此处采用0600(可读可写)的访问模式,所以代码如下:
case '>':
case '<':
rcmd = (struct redircmd*)cmd;
//fprintf(stderr, "redir not implemented\n");
// Your code here ...
//close current startdard input/output
close(rcmd->fd);
//open the target file,and give the startdard input/output to it
if(open(rcmd->file,rcmd->flags,0600)<0){
fprintf(stderr, "fail to open the file %s\n",rcmd->file);
exit(0);
}
//else exec the command
runcmd(rcmd->cmd);
break;
代码解释:因为每次分配文件描述符时都从最小的开始分配,因此关闭当前文件描述符后(标准输入/输出描述符),会将该关闭的描述符自动分配给当前打开的文件。执行结果如下;
可见,成功实现了重定向。
pipe管道的实现
什么是管道,见以下博文:https://www.jianshu.com/p/9c0c2b57cb73。该文章将什么是管道,已阐述得十分清楚。
实现需要用到dup方法,该方法的使用说明见博客:https://blog.csdn.net/silent123go/article/details/71108501。
实现需要用到fork方法,见博客:https://blog.csdn.net/weixin_30338481/article/details/97933030?utm_medium=distribute.pc_relevant.none-task-blog-title-2&spm=1001.2101.3001.4242。
故最后的实现为:
case '|':
pcmd = (struct pipecmd*)cmd;
//fprintf(stderr, "pipe not implemented\n");
// Your code here ...
//create a pipe
if(pipe(p)<0){
fprintf(stderr, "cannot create pipes\n");
exit(0);
}
//child proccess,read
if(fork1()==0){
//close read
close(0);
//child read point to pipe read
dup(p[0]);
//close pipe read and pipe write
close(p[0]);
close(p[1]);
runcmd(pcmd->right);
}
//parent process,write
else{
//close write
close(1);
//parent write point to pipe write
dup(p[1]);
//close pipe read and pipe write
close(p[0]);
close(p[1]);
runcmd(pcmd->left);
}
break;
执行结果:
注意必须在/usr/bin目录下执行该语句,不然找不到方法。显示的三个数字分别表示:行,字和总字母数。