不知不觉两周没有发文了,因为“一万美金的福特奖学金答辩”,ACM比赛,网络论文阅读和网络大作业一大堆事把时间冲散了,所以先写一篇博文补上之前一坑。
之前发了一篇关于linux 用C语言实现简单shell的博文,当时因为刚刚接触linux,只是处理了:
1)外部命令
2)pwd,cd,exit内置命令
3)输入输出重定向
并且代码相比较而言是一步一步添加的,代码相对来讲比较丑QAQ,所以在学完管道之后,相信不得不重新写代码才能实现了。
相比较之前的版本我对代码进行了相关的修改:
1)对于shell指令采用结构体存储,方便管道的切割与执行;
2)采用strtok_r对于指令进行了更加合理的切割;
3)增加了多管道处理;
4)处理了一些简单的异常问题,包括文件路径问题,空行问题,指令错误等。
评论中有朋友想让我加入后台运行‘&’功能的,其实基本上没什么区别,只是对于增加了‘&’后台运行的命令主进程不再需要等待子进程结束再操作了,我已经对我的代码进行了一些修改并加上一定的注释。
/*author:Samsons date:2015.4.28 1)对于shell指令采用结构体存储,方便管道的切割与执行; 2)采用strtok_r对于指令进行了更加合理的切割; 3)增加了多管道处理; 4)处理了一些简单的异常问题,包括文件路径问题,空行问题,指令错误等。
date:2015.4.30
增加了后台处理命令“&”的处理 */ #include <stdio.h> #include <signal.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <sys/wait.h> #define MAX 100 #define LEN 100 //shell指令单个管道结构体 struct cmd_list{ int argc; //单个管道参数个数 char *argv[MAX]; }; struct cmd_list *cmdv[MAX]; //shell指令 int num;//shell管道个数 int flagdo;//是否为后台处理命令标记 //执行外部命令 void execute(char *argv[]) { int error; error=execvp(argv[0],argv); if (error==-1) printf("failed! "); exit(1); } //切分单个管道 void split_cmd(char *line) { struct cmd_list * cmd = (struct cmd_list *)malloc(sizeof(struct cmd_list)); cmdv[num++] = cmd; cmd->argc = 0; char *save; char *arg = strtok_r(line, " ", &save);//切分空格 while (arg) { cmd->argv[cmd->argc] = arg; arg = strtok_r(NULL, " ", &save); cmd->argc++; } cmd->argv[cmd->argc] = NULL; } //切分管道 void split_pipe(char *line) { char *save; char * cmd = strtok_r(line, "|", &save); while (cmd) { split_cmd(cmd); cmd = strtok_r(NULL, "|", &save); } } //执行管道命令 void do_pipe(int index) { if (index == num - 1) execute(cmdv[index]->argv); int fd[2]; pipe(fd);//创建管道,0读,1写 if (fork() == 0) { dup2(fd[1], 1); close(fd[0]); close(fd[1]); execute(cmdv[index]->argv); } dup2(fd[0], 0); close(fd[0]); close(fd[1]); do_pipe(index + 1); } //执行内部指令 int inner(char *line) { char *save,*tmp[MAX]; char t[LEN],p[LEN]; strcpy(t,line); char *arg = strtok_r(line, " ", &save);//切分空格 int i=0; while (arg) { tmp[i] = arg; i++;//记录命令个数 arg = strtok_r(NULL, " ", &save); } tmp[i] = NULL; if (strcmp(tmp[i-1],"&")==0)//判断是否为后台处理命令 { flagdo=1; i--; } if (strcmp(tmp[0],"exit")==0)//exit { exit(0); return 1; } else if (strcmp(tmp[0],"pwd")==0)//pwd { char buf[LEN]; getcwd(buf,sizeof(buf));//得到当前路径 printf("Current dir is:%s ",buf); return 1; } else if (strcmp(tmp[0],"cd")==0)//cd { char buf[LEN]; if (chdir(tmp[1])>=0) { getcwd(buf,sizeof(buf)); printf("Current dir is:%s ",buf); } else { printf("Error path! "); } return 1; } else return 0; } //输入重定向 void cat_in(char *q) { char t[30]; int fd; if (q[0]=='<') { strcpy(t,q+1); fd=open(t,O_RDONLY); cmdv[0]->argv[cmdv[0]->argc-1]=NULL; //默认重定向为参数的最后一个 cmdv[0]->argc--; if (fd==-1) { printf("file open failed "); return; } dup2(fd,0); close(fd); } } //输出重定向 void cat_out(char *q) { char t[30]; int fd; if (q[0]=='>') { strcpy(t,q+1); cmdv[num-1]->argv[cmdv[num-1]->argc-1]=NULL; cmdv[num-1]->argc--; fd=open(t,O_CREAT|O_RDWR,0666); //0666为权限 if (fd==-1) { printf("file open failed "); return; } dup2(fd,1); close(fd); } } int main() { int i,pid; char buf[LEN],p[LEN]; while (1) { fgets(buf,LEN,stdin);//读入shell指令 if (buf[0]==' ') continue; buf[strlen(buf)-1]='