[英]c multiple pipes pipes and problems with file descriptor
你好,我对使用管道有些迷惑
我必须开发一个类似shell的程序,所以我已经有一个flex程序正在工作,并且表达式可以提供给该函数
编辑
正如dave指出的那样,我确实在函数内部声明了管道,但是我仍然遇到相同的问题,所以这是对函数的更新,我被卡在上面已经有一段时间了,好像我没有适当地关闭管道,因为第二个叉子总是挂在waitpid()上
但是我确实试图关闭主进程上的所有fork和所有子进程,但是第二个fork仍然挂着
int execute(Expression *e , int wait, int fdin,int fdout,int fderror){
int status;
pid_t childPID;
int fd;
int pp[2];
switch (e->type) {
case SIMPLE:
childPID = fork();
if(childPID >= 0) //fork was successful
{
if(childPID == 0) //child process
{
if(fdin != 0){
dup2(fdin,0);
close(fdin);
if(fdin > 2){
close(fdin +1);
}
}
if(fdout != 0){
dup2(fdout,1);
close(fdout);
if(fdout > 3){
close(fdout -1);
}
}
if(fderror != 2){
dup2(fderror,2);
close(fderror);
}
status = execvp(e->arguments[0], &e->arguments[0]);
perror(e->arguments[0]);
exit(1);
}
else//parent process
{
if(fdin > 2){
close(fdin);
close(fdin +1);
}
if(fdout > 3){
close(fdout);
close(fdout -1);
}
if(wait == 1){
printf("%s\n","going to wait" );
waitpid(childPID, &status, 0);
}
putchar('\n');
break;
}
}
else// fork failed
{
perror("fork");
}
break;
case SEQUENCE:
execute(e->gauche,1,fdin,fdout,fderror);
execute(e->droite,1,fdin,fdout,fderror);
break;
case SEQUENCE_ET:
execute(e->gauche,0,fdin,fdout,fderror);
execute(e->droite,1,fdin,fdout,fderror);
break;
case SEQUENCE_OU:
execute(e->gauche,0,fdin,fdout,fderror);
execute(e->droite,1,fdin,fdout,fderror);
break;
case BG:
execute(e->gauche,0,fdin,fdout,fderror);
break;
case PIPE:
if(pipe(pp) < 0){
perror("pipe");
exit(1);
}
execute(e->gauche,0,fdin,pp[1],fderror);
execute(e->droite,1,pp[0],fdout,fderror);
break;
case REDIRECTION_I:
fd = open(e->arguments[0],O_RDONLY, 0666);
execute(e->gauche,1,fd,fdout,fderror);
break;
case REDIRECTION_O:
fd = open(e->arguments[0],O_CREAT | O_RDWR, 0666);
execute(e->gauche,1,fdin,fd,fderror);
break;
case REDIRECTION_A:
fd = open(e->arguments[0], O_TRUNC | O_CREAT | O_RDWR, 0666);
execute(e->gauche,1,fdin,fd,fderror);
break;
case REDIRECTION_E:
fd = open(e->arguments[0], O_CREAT | O_RDWR, 0666);
execute(e->gauche,1,fdin,fdout,fd);
break;
case REDIRECTION_EO:
fd = open(e->arguments[0], O_CREAT | O_RDWR, 0666);
execute(e->gauche,1,fdin,fd,fd);
break;
default:
return 0;
break;
}
return 0;
}
我的问题是,这对于像
ls | grep a
操作系统
ls > test
但是如果我搞砸了,那就完全错了
例子
ls | grep a > test
我把输出放在终端上,而不是在文件中
或者如果我使用
ls | grep a | grep c
管道变得一团糟,我想我需要更多的管道来做,但是我不知道如何动态创建管道
谢谢大家
编辑
刚刚发现,在管道修复之后,我确实尝试了使用更大数据的命令,例如ls,而不是我在工作正常的文件上执行了cat命令,因此看起来该命令在任何数据到达管道之前就停止了
您正在为所有管道使用全局变量。 当您创建有ls | grep a
ls | grep a
那么您的全局管道可以正常工作。 但是,当您有多个管道时,可以将它们重复用于不同的目的! 解决方案是在函数中提取管道创建代码。 当您需要一个新管道时,在其中创建一个管道,并将正确的文件描述符传递给递归调用以execute
(这就是为什么需要fdin
和fdout
参数的原因。
所以我想我把它修好了
我的问题是在这种情况下,在启动最后一个fork之前调用了等待,在这种情况下,我确实添加了标志f来标识最后一个命令,并在最后一个命令上使用wait pid
这是代码
int execute(Expression *e , int wait, int fdin,int fdout,int fderror, int lastflag){
int status;
pid_t childPID;
int fd;
int pp[2];
switch (e->type) {
case SIMPLE:
childPID = fork();
if(childPID >= 0) //fork was successful
{
if(childPID == 0) //child process
{
if(fdin != 0){
dup2(fdin,0);
close(fdin);
}
if(fdout != 1){
dup2(fdout,1);
close(fdout);
}
if(fderror != 2){
dup2(fderror,2);
close(fderror);
}
for(int i = 3; i <= lastfd; i++){
close(i);
}
status = execvp(e->arguments[0], &e->arguments[0]);
perror(e->arguments[0]);
exit(1);
}
else//parent process
{
if(wait == 1){
for(int i = 3; i <= lastfd; i++){
close(i);
}
printf("%s\n","going to wait" );
waitpid(childPID, &status, WNOHANG);
}
putchar('\n');
break;
}
}
else// fork failed
{
perror("fork");
}
break;
case SEQUENCE:
execute(e->gauche,1,fdin,fdout,fderror,0);
execute(e->droite,1,fdin,fdout,fderror,0);
break;
case SEQUENCE_ET:
execute(e->gauche,0,fdin,fdout,fderror,0);
execute(e->droite,1,fdin,fdout,fderror,0);
break;
case SEQUENCE_OU:
execute(e->gauche,0,fdin,fdout,fderror,0);
execute(e->droite,1,fdin,fdout,fderror,0);
break;
case BG:
execute(e->gauche,0,fdin,fdout,fderror,0);
break;
case PIPE:
if(pipe(pp) < 0){
perror("pipe");
exit(1);
}
ch_lastfd(pp[1]);
execute(e->gauche,0,fdin,pp[1],fderror,0);
if(lastflag == 1){
execute(e->droite,1,pp[0],fdout,fderror,0);
}else{
execute(e->droite,0,pp[0],fdout,fderror,0);
}
break;
case REDIRECTION_I:
fd = open(e->arguments[0],O_RDONLY, 0666);
ch_lastfd(fd);
execute(e->gauche,1,fd,fdout,fderror,0);
break;
case REDIRECTION_O:
fd = open(e->arguments[0],O_CREAT | O_RDWR, 0666);
ch_lastfd(fd);
execute(e->gauche,1,fdin,fd,fderror,0);
break;
case REDIRECTION_A:
fd = open(e->arguments[0], O_TRUNC | O_CREAT | O_RDWR, 0666);
ch_lastfd(fd);
execute(e->gauche,1,fdin,fd,fderror,0);
break;
case REDIRECTION_E:
fd = open(e->arguments[0], O_CREAT | O_RDWR, 0666);
ch_lastfd(fd);
execute(e->gauche,1,fdin,fdout,fd,0);
break;
case REDIRECTION_EO:
fd = open(e->arguments[0], O_CREAT | O_RDWR, 0666);
ch_lastfd(fd);
execute(e->gauche,1,fdin,fd,fd,0);
break;
default:
break;
}
return 0;
}
可能不是实现它的最佳方法,所以如果有人有任何想法如何使其变得更好,我欢迎您提出建议,谢谢
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.