首先总结一下思路:
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);
}
}
以上为运行结果。