wc: '标准输入':错误的文件描述符

发布于 2025-01-17 12:51:08 字数 1677 浏览 3 评论 0原文

我正在使用 Exec 系列函数模拟 C 语言中的 bash 命令。

这只是更大项目的部分代码。为了简单起见,现在大多数内容都是硬编码的,但将来我需要使用管道或重定向运算符执行任何 bash 命令,这就是代码循环的原因。我知道我可以使用单个文件描述符(不带二维数组)来实现当前示例的结果,但我需要概括多个 |, > 的代码命令。我无法删除循环。

即使正确关闭所有描述符后,我也会收到“错误描述符”错误。无法找到原因。

int main()
{
    int numOfCmds = 2;
    int numOfPipes = numOfCmds -1;
    int pipes[numOfPipes][2];

    for(int i=0;i<numOfPipes;i++)
        if(pipe(pipes[i])<0) return 1;

    for(int i=0;i<numOfCmds;i++)
    {
        int child = fork();
        if(child == 0)
        {
            if(i==0)
            {
                for(int i=0;i<numOfPipes;i++)
                {
                    close(pipes[i][0]);
                }
                printf("hey\n");
                dup2(pipes[i][1], STDOUT_FILENO);
                close(pipes[i][1]);
                char *cmd1_args[3] = {"ls", "-l", NULL};
                execvp(cmd1_args[0], cmd1_args);
            }
            if(i==1)
            {
                for(int i=0;i<numOfPipes;i++)
                {
                    close(pipes[i][1]);
                }
                printf("bye\n");
                dup2(pipes[i][0], STDIN_FILENO);
                close(pipes[i][0]);
                char *cmd2_args[3] = {"wc", "-l", NULL};
                execvp(cmd2_args[0], cmd2_args);
            }

            return 0;
        }
    }
    for(int i=0;i<numOfCmds;i++)
    {
        for(int j=0;i<2;j++)
            close(pipes[i][j]);
    }

    for(int i=0;i<numOfCmds;i++) wait(NULL);

    return 0;

错误:

嘿再见 wc: '标准输入': 错误文件描述符 0 wc: -: 错误文件 描述符分段错误(核心转储)

I'm emulating bash commands in C language using Exec family of functions.

This is just a partial code of bigger project. Most of the things are hard-coded for now for simplicity, but in future I need to execute any bash command with Pipe or Redirection operator so that's the reason the code is in loop. I know I can use single file descriptor(with out 2d array) to achieve the result for current example but I need to generalise the code for multiple |, > commands. I can't remove the loop.

I'm getting Bad descriptor error even after closing all the descriptors correctly. Unable to find the reason.

int main()
{
    int numOfCmds = 2;
    int numOfPipes = numOfCmds -1;
    int pipes[numOfPipes][2];

    for(int i=0;i<numOfPipes;i++)
        if(pipe(pipes[i])<0) return 1;

    for(int i=0;i<numOfCmds;i++)
    {
        int child = fork();
        if(child == 0)
        {
            if(i==0)
            {
                for(int i=0;i<numOfPipes;i++)
                {
                    close(pipes[i][0]);
                }
                printf("hey\n");
                dup2(pipes[i][1], STDOUT_FILENO);
                close(pipes[i][1]);
                char *cmd1_args[3] = {"ls", "-l", NULL};
                execvp(cmd1_args[0], cmd1_args);
            }
            if(i==1)
            {
                for(int i=0;i<numOfPipes;i++)
                {
                    close(pipes[i][1]);
                }
                printf("bye\n");
                dup2(pipes[i][0], STDIN_FILENO);
                close(pipes[i][0]);
                char *cmd2_args[3] = {"wc", "-l", NULL};
                execvp(cmd2_args[0], cmd2_args);
            }

            return 0;
        }
    }
    for(int i=0;i<numOfCmds;i++)
    {
        for(int j=0;i<2;j++)
            close(pipes[i][j]);
    }

    for(int i=0;i<numOfCmds;i++) wait(NULL);

    return 0;

Error:

hey bye wc: 'standard input': Bad file descriptor 0 wc: -: Bad file
descriptor Segmentation fault (core dumped)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

空城缀染半城烟沙 2025-01-24 12:51:08

您的问题是您正在重复使用i的(嵌套)定义。使用-wshadow对GCC的选项避免这样做。 i的值有时超出了一对文件描述符数组的末尾,这会导致混乱(未定义的行为)。

您有:

    for(int i=0;i<numOfCmds;i++)
    {
        int child = fork();
        if(child == 0)
        {
            if(i==0)
            {
                for(int i=0;i<numOfPipes;i++)
                {
                    close(pipes[i][0]);
                }
                printf("hey\n");
                dup2(pipes[i][1], STDOUT_FILENO);
                close(pipes[i][1]);
                char *cmd1_args[3] = {"ls", "-l", NULL};
                execvp(cmd1_args[0], cmd1_args);
            }
            if(i==1)
            {
                for(int i=0;i<numOfPipes;i++)
                {
                    close(pipes[i][1]);
                }
                printf("bye\n");
                dup2(pipes[i][0], STDIN_FILENO);
                close(pipes[i][0]);
                char *cmd2_args[3] = {"wc", "-l", NULL};
                execvp(cmd2_args[0], cmd2_args);
            }

            return 0;
        }
    }

您的(外)循环控制变量为i;然后,您拥有一个由不同的i控制的内部循环,该循环关闭了一些管道。我使用的GCC报告说,您正在访问管道[i] [0]dup2() wc的范围中。

您需要重新使用i的使用(使用一些不同的名称 - jk(对于'Kids'?)是可用的)。并重新审查您要仔细关闭的文件描述符。

您的父母循环关闭文件描述符是:

    for(int i=0;i<numOfCmds;i++)
    {
        for(int j=0;i<2;j++)
            close(pipes[i][j]);
    }

您需要使用numofpipes而不是numofcmds,并且您需要内部循环来测试 j ,而不是i

这是一些有效的仪器代码。但是这些修复程序不是很通用:

/* SO 7165-1018 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    int numOfCmds = 2;
    int numOfPipes = numOfCmds - 1;
    int pipes[numOfPipes][2];

    for(int i=0;i<numOfPipes;i++)
        if(pipe(pipes[i])<0) return 1;

    for (int i = 0; i < numOfPipes; i++)
        printf("%d: pipe[%d][0] = %d; pipe[%d][1] = %d\n",
               getpid(), i, pipes[i][0], i, pipes[i][1]);

    for(int i=0;i<numOfCmds;i++)
    {
        int child = fork();
        printf("%d: child = %d\n", getpid(), child);
        if(child == 0)
        {
            if(i==0)
            {
                for(int i=0;i<numOfPipes;i++)
                {
                    printf("%d: ls: close %d\n", getpid(), pipes[i][0]);
                    close(pipes[i][0]);
                }
                printf("%d: hey\n", getpid());
                dup2(pipes[i][1], STDOUT_FILENO);
                printf("%d: ls: close %d\n", getpid(), pipes[i][1]);
                close(pipes[i][1]);
                char *cmd1_args[3] = {"ls", "-l", NULL};
                execvp(cmd1_args[0], cmd1_args);
                fprintf(stderr, "failed to execute %s\n", cmd1_args[0]);
                exit(EXIT_FAILURE);
            }
            if(i==1)
            {
                for(int i=0;i<numOfPipes;i++)
                {
                    printf("%d: wc: close %d\n", getpid(), pipes[i][1]);
                    close(pipes[i][1]);
                }
                printf("%d: bye\n", getpid());
                dup2(pipes[0][0], STDIN_FILENO);
                printf("%d: wc: close %d\n", getpid(), pipes[0][0]);
                close(pipes[0][0]);
                char *cmd2_args[3] = {"wc", "-l", NULL};
                execvp(cmd2_args[0], cmd2_args);
                fprintf(stderr, "failed to execute %s\n", cmd2_args[0]);
                exit(EXIT_FAILURE);
            }

            return 0;
        }
    }

    for(int i=0;i<numOfPipes;i++)
    {
        for(int j=0;j<2;j++)
        {
            printf("parent (%d): close %d\n", getpid(), pipes[i][j]);
            close(pipes[i][j]);
        }
    }

    for(int i=0;i<numOfCmds;i++)
    {
        int corpse;
        int status;
        if ((corpse = wait(&status)) > 0)
            printf("%d: child %d exited with status 0x%.4X\n", getpid(), corpse, status);
    }

    return 0;
}

一个示例运行(程序sh83,根据sh83.c )产生:

42654: pipe[0][0] = 3; pipe[0][1] = 4
42654: child = 42655
42655: child = 0
42655: ls: close 3
42654: child = 42656
parent (42654): close 3
parent (42654): close 4
42655: hey
42656: child = 0
42656: wc: close 4
42656: bye
42656: wc: close 3
     128
42654: child 42655 exited with status 0x0000
42654: child 42656 exited with status 0x0000

如果您使用多个进程,我会发现它如输出所示,可以将大多数消息的前缀前缀前缀。

Your problem is that you are reusing (nested) definitions of i. Use the -Wshadow option to GCC to avoid doing that. And the value of i is sometimes beyond the end of the array of pairs of file descriptors, which leads to chaos (undefined behaviour).

You have:

    for(int i=0;i<numOfCmds;i++)
    {
        int child = fork();
        if(child == 0)
        {
            if(i==0)
            {
                for(int i=0;i<numOfPipes;i++)
                {
                    close(pipes[i][0]);
                }
                printf("hey\n");
                dup2(pipes[i][1], STDOUT_FILENO);
                close(pipes[i][1]);
                char *cmd1_args[3] = {"ls", "-l", NULL};
                execvp(cmd1_args[0], cmd1_args);
            }
            if(i==1)
            {
                for(int i=0;i<numOfPipes;i++)
                {
                    close(pipes[i][1]);
                }
                printf("bye\n");
                dup2(pipes[i][0], STDIN_FILENO);
                close(pipes[i][0]);
                char *cmd2_args[3] = {"wc", "-l", NULL};
                execvp(cmd2_args[0], cmd2_args);
            }

            return 0;
        }
    }

Your (outer) loop control variable is i; you then have an inner loop controlled by a different i that closes some pipes. And the GCC I use reports that you are accessing pipes[i][0] out of bounds in the dup2() call for wc.

You need to rework your use of i (use some different names — j and k (for 'kids'?) are usable). And re-review which file pipe descriptors you are closing carefully.

Your parental loop closing file descriptors is:

    for(int i=0;i<numOfCmds;i++)
    {
        for(int j=0;i<2;j++)
            close(pipes[i][j]);
    }

You need to use the numOfPipes instead of numOfCmds, and you need your inner loop to test j, not i.

Here's some heavily instrumented code that works. But the fixes are not very general:

/* SO 7165-1018 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    int numOfCmds = 2;
    int numOfPipes = numOfCmds - 1;
    int pipes[numOfPipes][2];

    for(int i=0;i<numOfPipes;i++)
        if(pipe(pipes[i])<0) return 1;

    for (int i = 0; i < numOfPipes; i++)
        printf("%d: pipe[%d][0] = %d; pipe[%d][1] = %d\n",
               getpid(), i, pipes[i][0], i, pipes[i][1]);

    for(int i=0;i<numOfCmds;i++)
    {
        int child = fork();
        printf("%d: child = %d\n", getpid(), child);
        if(child == 0)
        {
            if(i==0)
            {
                for(int i=0;i<numOfPipes;i++)
                {
                    printf("%d: ls: close %d\n", getpid(), pipes[i][0]);
                    close(pipes[i][0]);
                }
                printf("%d: hey\n", getpid());
                dup2(pipes[i][1], STDOUT_FILENO);
                printf("%d: ls: close %d\n", getpid(), pipes[i][1]);
                close(pipes[i][1]);
                char *cmd1_args[3] = {"ls", "-l", NULL};
                execvp(cmd1_args[0], cmd1_args);
                fprintf(stderr, "failed to execute %s\n", cmd1_args[0]);
                exit(EXIT_FAILURE);
            }
            if(i==1)
            {
                for(int i=0;i<numOfPipes;i++)
                {
                    printf("%d: wc: close %d\n", getpid(), pipes[i][1]);
                    close(pipes[i][1]);
                }
                printf("%d: bye\n", getpid());
                dup2(pipes[0][0], STDIN_FILENO);
                printf("%d: wc: close %d\n", getpid(), pipes[0][0]);
                close(pipes[0][0]);
                char *cmd2_args[3] = {"wc", "-l", NULL};
                execvp(cmd2_args[0], cmd2_args);
                fprintf(stderr, "failed to execute %s\n", cmd2_args[0]);
                exit(EXIT_FAILURE);
            }

            return 0;
        }
    }

    for(int i=0;i<numOfPipes;i++)
    {
        for(int j=0;j<2;j++)
        {
            printf("parent (%d): close %d\n", getpid(), pipes[i][j]);
            close(pipes[i][j]);
        }
    }

    for(int i=0;i<numOfCmds;i++)
    {
        int corpse;
        int status;
        if ((corpse = wait(&status)) > 0)
            printf("%d: child %d exited with status 0x%.4X\n", getpid(), corpse, status);
    }

    return 0;
}

One sample run (of program sh83, compiled from sh83.c) yielded:

42654: pipe[0][0] = 3; pipe[0][1] = 4
42654: child = 42655
42655: child = 0
42655: ls: close 3
42654: child = 42656
parent (42654): close 3
parent (42654): close 4
42655: hey
42656: child = 0
42656: wc: close 4
42656: bye
42656: wc: close 3
     128
42654: child 42655 exited with status 0x0000
42654: child 42656 exited with status 0x0000

If you're working with multiple processes, I find it is a great help to prefix most messages with a PID — as shown in the output.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文