使用Execvp、fork和pipe的递归管道函数中存在错误的文件描述符
我正在尝试使用使用Execvp、fork和pipe的递归管道函数中存在错误的文件描述符,c,pipe,fork,dup2,C,Pipe,Fork,Dup2,我正在尝试使用dup2()、fork()和pipe()创建递归管道函数。但是,当我的数组类似于{“ls”,“grepshell”}(其中shell是我的shell的名称)时,它会进入一个无休止的循环,显示ls的结果并说“write error:bad file descriptor”。我确信我没有正确地终止我的递归,我怀疑问题在于尝试重复fd[1]或fd[0],但在调试了几个小时后,我仍然无法找到它。感谢您的帮助 void recursive_piping(char *recursive_pip
dup2()
、fork()
和pipe()
创建递归管道函数。但是,当我的数组类似于{“ls”,“grepshell”}
(其中shell是我的shell的名称)时,它会进入一个无休止的循环,显示ls的结果并说“write error:bad file descriptor”。我确信我没有正确地终止我的递归,我怀疑问题在于尝试重复fd[1]
或fd[0]
,但在调试了几个小时后,我仍然无法找到它。感谢您的帮助
void recursive_piping(char *recursive_pipe_args[MAX_ARGS]) {
int i = 0;
int fd[2];
char *first_arg[2] = {"", NULL};
char *rest_of_args[81];
// if its of size 1, base case
if (recursive_pipe_args[1] == NULL) {
if (execvp(recursive_pipe_args[0], recursive_pipe_args) == -1) {
printf("\nExecute didn't work");
fflush(stdout);
}
return;
}
// recursive case, split args into the first on and the rest of them
first_arg[0] = recursive_pipe_args[0];
for (i = 0; i < (num_pipes); i++) {
rest_of_args[i] = malloc(81);
strcpy(rest_of_args[i], recursive_pipe_args[i+1]);
}
if (pipe(fd) < 0) {
printf("\npipe Failure");
}
// parent section, reads file descriptor fd[0]
if (fork()) {
close(fd[0]);
dup2(fd[1], 0);
recursive_piping(rest_of_args);
// return;
}
close(fd[1]);
dup2(fd[0], 1);
execvp(first_arg[0], first_arg);
}
无效递归管道(字符*递归管道参数[最大参数]){
int i=0;
int-fd[2];
char*first_arg[2]={“”,NULL};
字符*参数的剩余部分[81];
//如果其大小为1,则为基本情况
if(递归管道参数[1]==NULL){
if(execvp(递归管道参数[0],递归管道参数)=-1){
printf(“\nExecute不起作用”);
fflush(stdout);
}
返回;
}
//递归情况下,将arg拆分为第一个on和其余的
第一个参数[0]=递归管道参数[0];
对于(i=0;i<(管道数);i++){
剩余的参数[i]=malloc(81);
strcpy(剩余参数[i],递归参数[i+1]);
}
如果(管道(fd)<0){
printf(“\n管道故障”);
}
//父节,读取文件描述符fd[0]
if(fork()){
关闭(fd[0]);
dup2(fd[1],0);
递归管道(其余参数);
//返回;
}
关闭(fd[1]);
dup2(fd[0],1);
execvp(第一个参数[0],第一个参数);
}
我用这些更改为您的函数准备了一个变体:
- 它为
的第一个元素recursive\u pipe\u args
添加了一个检查,在这种情况下,它会在不执行任何操作的情况下发出诊断NULL
- 它统计
数组中初始非空元素的数量,并动态分配recursive\u pipe\u args
(从而允许一个更少的参数加上rest\u个具有该容量的\u args
哨兵的空间)NULL
- 它根据前者元素的实际计数,将递归参数的尾部复制到参数的剩余部分,从而确保复制
哨兵NULL
- 它识别并处理
中的错误fork()
- 它更正复制,以便将每个管道的写入端(
)复制到标准输出(文件描述符fd[1]
),将读取端复制到标准输入端(1
和fd[0]
),并在每个进程中关闭该进程中未使用的管道端0
- 它将错误消息写入标准错误流而不是标准输出,并尽可能依赖
peror()
{“ls”,“wc”}
实现这些更改的代码留作练习。
if(fork())…
Ouch。你想过如果fork()
失败会发生什么吗?啊,说实话,不是真的。什么是num_pipes
?你正在将管道的读取端复制到预期用于输出的文件描述符上,反之亦然。这可能是“错误的文件描述符”错误的根本原因。是的,@Roug,当您通过shell执行该命令时,shell会将“grep shell”解析为命令名“grep”和一个参数“shell”。这是在shell中实现的,而不是在底层exec调用中实现的。