dup2 错误的文件描述符错误

Posted

技术标签:

【中文标题】dup2 错误的文件描述符错误【英文标题】:dup2 bad file descriptor error 【发布时间】:2011-12-08 09:29:45 【问题描述】:

我正在尝试使用从website 获得的教程来实现多个管道。在执行处理多个管道的函数后,我似乎遇到了错误的文件描述符错误。当我第一次欺骗时,它会向我发送此错误。代码如下:

void runPipedCommands(cmdLine* command, char* userInput) 
    int numPipes = countPipes(userInput);

    int status = 0;
    int i = 0, j = 0;

    pid_t pid;

    int pipefds[2*numPipes];

    for(i = 0; i < (numPipes); i++)
        if(pipe(pipefds + i*2) < 0) 
            perror("pipe");
            exit(EXIT_FAILURE);
        
    

    j = 0;
    while(command) 
        pid = fork();
        if(pid == 0) 

            //if not first command
            if(j != 0)
                if(dup2(pipefds[j-2], 0) < 0)
                    perror(" dup2");///j-2 0 j+1 1
                    exit(EXIT_FAILURE);

                

            if(command->next)
                printf(
                if(dup2(pipefds[j + 1], 1) < 0)
                    perror("dup2");
                    exit(EXIT_FAILURE);
                
            

            for(i = 0; i < 2*numPipes; i++)
                    close(pipefds[i]);
            

            if( execvp(*command->arguments, command->arguments) < 0 )
                    perror(*command->arguments);
                    exit(EXIT_FAILURE);
            
         else if(pid < 0)
            perror("error");
            exit(EXIT_FAILURE);
        

        command = command->next;
        j++;
    
        for(i = 0; i < 2 * numPipes; i++)
            close(pipefds[i]);
            printf("in parent: closed pipe[%d]\n", i);
        
        wait(0);
    

也许某处有泄漏,或者找不到描述符。我似乎不知道问题出在哪里。我做错了什么?谢谢。

修改后的代码:

void runPipedCommands(cmdLine* command, char* userInput) 
    int numPipes = countPipes(userInput);

    int status = 0;
    int i = 0, j = 0;

    pid_t pid;

    int pipefds[2*numPipes];

    for(i = 0; i < (numPipes); i++)
        if(pipe(pipefds + i*2) < 0) 
            perror("pipe");
            exit(EXIT_FAILURE);
        
    

    j = 0;
    while(command) 
        pid = fork();
        if(pid == 0) 
            //if not first command
            if(j != 0 && j!= 2*numPipes)
                if(dup2(pipefds[j-2], 0) < 0)
                    perror(" dup2");///j-2 0 j+1 1
                    exit(EXIT_FAILURE);

                
            

            //if not last command
            if(command->next)
                printf("command exists: dup(pipefd[%d], 1])\n", j+1);
                if(dup2(pipefds[j + 1], 1) < 0)
                    perror("dup2");
                    exit(EXIT_FAILURE);
                
            

            for(i = 0; i < 2*numPipes; i++)
                    close(pipefds[i]);
                   printf("in child: closed pipe[%d]\n", i);
            

            if( execvp(*command->arguments, command->arguments) < 0 )
                    perror(*command->arguments);
                    exit(EXIT_FAILURE);
            
         else if(pid < 0)
            perror("error");
            exit(EXIT_FAILURE);
        

        command = command->next;
        j+=2;
    
        for(i = 0; i < 2 * numPipes; i++)
            close(pipefds[i]);
            printf("in parent: closed pipe[%d]\n", i);
           
           wait(0);
    

【问题讨论】:

你得到什么错误?在哪里? @sarnold:我在dup2(pipefds[j-2], 0) 收到dup2: bad file descriptor 这是相当混乱的代码;我试了一下,但您最好通过strace(1)ltrace(1)gdb(1) 运行它,并观察它们的每一步。 【参考方案1】:

好的,首先,有点奇怪 - 您的嵌套与您的大括号不对齐。 if (j != 0)if(command-&gt;next) 看起来像同一个“级别”,但实际的大括号讲述的是不同的故事:

复制粘贴:

        if(j != 0)
            if(dup2(pipefds[j-2], 0) < 0)
                perror(" dup2");///j-2 0 j+1 1
                exit(EXIT_FAILURE);
            

        if(command->next)
            printf(
            if(dup2(pipefds[j + 1], 1) < 0)
                perror("dup2");
                exit(EXIT_FAILURE);
            
        

重新缩进以反映大括号:

if (j != 0) 
    if (dup2(pipefds[j - 2], 0) < 0) 
        perror(" dup2");    ///j-2 0 j+1 1
        exit(EXIT_FAILURE);
    

    if (command->next) 
        printf(); /* fixed this */
        if (dup2(pipefds[j + 1], 1) < 0) 
            perror("dup2");
            exit(EXIT_FAILURE);
        
    

请让您的 IDE、编辑器或 indent(1) 重新缩进您的代码以反映代码的实际语法,以免您被误导性的空格弄糊涂。

其次,我认为您在较早的迭代中将 j+=2j++ 更改了,但并没有完全这样做——在第一次通话中,您使用的是 pipefds[j-2],而在下一次通话中,您将使用“重新使用pipefds[j+1]。在第一次迭代中j-1 发生了什么?它被忽略。这是故意的吗? j 仅在 next 迭代中被引用(通过 j+=2 .. [j-2])。任何东西都会引用pipefds[] 中的倒数第二个条目吗?这也是故意的吗?

【讨论】:

天哪。谢谢。我没有注意到这一点。是的,我的牙套嵌套不好。现在纠正他们。其次,是的,我确实从早期代码中更改了j+=2from a j++。我已经改回来了。实际上我使用j 来检查当前命令是否不是第一个命令。如果不是我重复,否则我不会。所以这解决了坏文件描述符的问题。 Will anything ever reference the next-to-last entry in pipefds[] 是什么意思? 哦。你的意思是我如何检查它是否是堆栈上的最后一个命令?是的,我需要检查一下。这不是故意的。我没想到...粗心的我。 if(j != 0 &amp;&amp; j!= numPipes -1) 会吗? 对于next-to-last entry in pipefds[],它只是注意到你有一个“滑动窗口”,适用于j-2j+1,并将j增加@987654343 @(并跳过第一个 j==0)。这将 选择 [ 0, 1, 2, 3, 4, 5, 6, 7 ] 当numPipes==4. (在一张纸上为j-2j+1 剪洞,然后沿着文本滑动。)也许这是故意的,也许不是,但我已经没有足够的脑力来确定了。 :) 这不是故意的。实际上我不再使用j+=2。我现在使用j++。当我使用j+2 时,我调用了dup2(pipefds[(j-1) * 2])dup2(pipefds[j * 2 + 1], 1)。那时就是这样。但现在我将坚持使用j++ 并使用j-2j+1。哦,请不要现在用尽脑力:)。我还需要一些帮助。纠正一切后,管道无法正常工作。当我输入ls | grep bin 之类的内容时,找不到任何结果。当我想输入另一个命令时,它会挂起。 等等,我在上面写了废话。目前,在更改代码后,我使用j+=2 递增并调用(dup2(pipefds[j-2], 0) (dup2(pipefds[j+1], 1)【参考方案2】:

这是问题的答案。希望它可以帮助那里的人。我最终决定将 j 增加 2 (j+=2)。函数countPipes(char*) 只是一个简单的函数,用于从char* 中计算管道(|) 的数量

void runPipedCommands(cmdLine* command, char* userInput) 
    int numPipes = countPipes(userInput);

    int status;
    int i = 0;
    pid_t pid;

    int pipefds[2*numPipes];//declare pipes

    /**Set up pipes*/
    for(i = 0; i < (numPipes); i++)
        if(pipe(pipefds + i*2) < 0) 
            perror("couldn't pipe");
            exit(EXIT_FAILURE);
        
    

    int j = 0;
    while(command) 
        pid = fork();
        if(pid == 0) 

            //if not last command
            if(command->next)
                if(dup2(pipefds[j + 1], 1) < 0)
                    perror("dup2");
                    exit(EXIT_FAILURE);
                
            

            //if not first command
            if(j != 0 )
                if(dup2(pipefds[j-2], 0) < 0)
                    perror(" dup2");///j-2 0 j+1 1
                    exit(EXIT_FAILURE);

                
            

            //close pipes in child
            for(i = 0; i < 2*numPipes; i++)
                    close(pipefds[i]);
            

            //execute commands
            if( execvp(*command->arguments, command->arguments) < 0 )
                    perror(*command->arguments);
                    exit(EXIT_FAILURE);
            
         else if(pid < 0)
            perror("error");
            exit(EXIT_FAILURE);
        

        command = command->next;//go to the next command in the linked list
        j+=2;//increment j
    

    /**Parent closes the pipes and waits for all of its children*/

    for(i = 0; i < 2 * numPipes; i++)
        close(pipefds[i]);
    

    for(i = 0; i < numPipes + 1; i++) //parent waits for all of its children
        wait(&status);

【讨论】:

以上是关于dup2 错误的文件描述符错误的主要内容,如果未能解决你的问题,请参考以下文章

linux之dup和dup2函数解析

dup/dup2输出重定向

UNIX 文件描述符重用

dup/dup2

文件描述符的复制——实现输出重定向

Linux dup dup2函数理解