实验出处shell
1.准备阶段
ps:(如果想直接看源码解析请跳转到目录2.源码解析)
1.1 文件I/O(文件重定向)
文件描述符:STDIN_FILENO ---------- 0
STDOUT_FILENO---------- 1
STDERR_FILENO---------- 2
文件描述符的范围是0~OPEN_MAX
重定向分为 “<", “>”,"<<",">>"
cmd < file: 将文件作为命令的标准输入
cmd < file1 > file2:将文件1作为命令的标准输入,将标准输出重定向到文件2中
1.2 管道
管道:进程通讯工具 半双工通讯
如: ls | wc
将ls的输出流入到管道中,在从管道流出到wc,知道这些我们将引出pipe()函数
int p[2]; //数组用来存储一对文件描述符
pipe(p);
p[0]; //流入管道中的信息
p[1]; //流出管道中的信息
1.3 函数准备
需要认识的函数(均在unix高级编程这本书中可以查阅)
pipe();
access();
dup();
exec(); //系列函数
close();
fork();
fprintf();
这些函数需要细致的弄清楚
2.源码解析(这里我们只提供需要coding的部分)
2.1执行部分
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)==0){
execv(ecmd->argv[0],ecmd->argv); //判断文件是否存在 存在就执行
}else{
const char* path_get[] = {"/bin/","/usr/bin/"}; //不存在的原因可能是绝对路径的选择,通过数组中绝对路径的选择来再次判断执行
char* abs_path;
int found = 0; //只要找到一个就停止寻找了
int path_count = sizeof(path_get) / sizeof(path_get[0]);
for(int i = 0;i<path_count && found==0;i++){
int len = strlen(path_get[i]) + strlen(ecmd->argv[0]);
abs_path = (char *)malloc(len+1*sizeof(char));
strcpy(abs_path,path_get[i]);
strcat(abs_path,ecmd->argv[0]);
if(access(abs_path,F_OK)==0)
execv(abs_path,ecmd->argv); //正确的绝对路径并且执行
found = 1;
}
free(abs_path);
}
break;
2.2 重定向部分
case '<':
rcmd = (struct redircmd*)cmd;
// fprintf(stderr, "redir not implemented\n");
// Your code here ...
close(rcmd->fd); //关闭一开始的文件描述符
if(open(rcmd->file,rcmd->flags, 0644)<0){ //打开文件到标准输入中
fprintf(stderr,"open file: %s failed",rcmd->file);
exit(0);
}
runcmd(rcmd->cmd);
break;
2.3管道部分
case '|':
pcmd = (struct pipecmd*)cmd;
// fprintf(stderr, "pipe not implemented\n");
// Your code here ...
if(pipe(p) < 0)
fprintf(stderr,"pipe failed\n");
if(fork1()==0){
close(0); //关闭标准输入
dup(p[0]); //p[0]代表流出管道流出进入右边的命令
close(p[0]);
close(p[1]);
runcmd(pcmd->right);
}else { //此时考虑命令流入pipe中 cmd |
close(1); //关闭标准输出
dup(p[1]); //p[1]代表流入左边命令流入管道
close(p[0]);
close(p[1]);
runcmd(pcmd->left);
}
break;