首先总结一下思路:
1. 如果要支持管道就首先需要分析命令中是否包含管道。(使用stringcmp函数)
2.如果包含管道就将管道符号位置为NULL,然后将管道符号前后的命令分到两个指针数组中 即:tmp1[ ]和tmp2[ ]
3.这个时候需要执行两个execvp函数,我们为了保证循环的进程不会被替换,需要fork两次,分别用孙子进程执行tmp1[ ]和子进程执行tmp2[ ]。
4.关于管道创建的位置(很关键),创建的位置要在儿子进程中,并且在孙子进程创建之前。(在其他位置会发生不知名错误)。
父进程等待就行了。
以下是代码
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<sys/wait.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> void do_parse(char *buf,char* argv[]) { if(buf==NULL) { return; } if(argv==NULL) { return; } int i; int argc=0; int status=0; for(i=0;buf[i];i++) { if( !isspace(buf[i]) && status==0) { argv[argc++]=buf+i; status=1; }else if( isspace(buf[i]) ) { status=0; buf[i]='\0'; } } argv[argc]=NULL; } int has_pipe(char* argv[]) { int i=1; //Start form 1 because before '|' should have command. while(argv[i]!=NULL) { if(strcmp(argv[i],"|")==0) { argv[i]=NULL; return i+1; } i++; } return 0; } int main() { char* argv[16]; int argc = 0; char buf[1024]={0}; char* tmp1[8]; char* tmp2[8]; int fd[2]; int ret; while(1) { printf("[myshell~]"); scanf("%[^\n]%*c",buf); do_parse(buf,argv); ret=has_pipe(argv); if(ret) { int i=0; int j=ret; // divide argv to tmp1 and tmp2. while(argv[i]!=NULL) { tmp1[i]=argv[i]; i++; } tmp1[i]=NULL; i=0; while(argv[j]!=NULL) { tmp2[i++]=argv[j++]; } tmp2[i]=NULL; // creat son process. pid_t pid_p=fork(); if(pid_p==-1) { perror("pid_p"); exit(EXIT_FAILURE); } else if(pid_p==0) {//son if(pipe(fd)==-1) { perror("pipe"); exit(EXIT_FAILURE); } // creat grandson process. pid_t pid_s=fork(); if(pid_s==-1) { perror("pid_s"); exit(EXIT_FAILURE); } else if(pid_s==0) { //grand son close(fd[0]); dup2(fd[1],1); execvp(tmp1[0],tmp1); } else { //son close(fd[1]); dup2(fd[0],0); execvp(tmp2[0],tmp2); } }else{ //fater wait(NULL); } //two execvp to do the work. } else {// no pipe pid_t pid=fork(); if(pid==-1) { perror("pid"); exit(EXIT_FAILURE); } else if(pid==0) { execvp(argv[0],argv); }else{ wait(NULL); } } memset(buf,0,1024); } }以上为运行结果。
