ls | wc使用C';行不通

ls | wc使用C';行不通,c,pipe,C,Pipe,我已经写了一个C程序,它使用多个管道来模拟外壳。问题是我可以运行大多数命令,如ls | cat等,但我无法使用ls | wc。是否存在wc不工作的情况 int pipefd[4]; int p1 = pipe(pipefd); // Open pipe 1 int p2 = pipe(pipefd + 2); // Open pipe 2 pid_t pid; for(i = 0; i < n_commands; i++) { fflush(std

我已经写了一个C程序,它使用多个管道来模拟外壳。问题是我可以运行大多数命令,如
ls | cat
等,但我无法使用
ls | wc
。是否存在
wc
不工作的情况

int pipefd[4]; 
int p1 = pipe(pipefd);          // Open pipe 1
int p2 = pipe(pipefd + 2);      // Open pipe 2

pid_t pid;

for(i = 0; i < n_commands; i++)
{
    fflush(stdout);
    pid = fork();

    if(pid == 0)
    {
        int command_no = i;
        int prev_pipe = ((command_no - 1) % 2) * 2;
        int current_pipe = (command_no % 2) * 2;

        // If current command is the first command, close the
        // read end, else read from the last command's pipe
        if(command_no == 0)
        {
            close(pipefd[0]);
        }
        else
        {
            dup2(pipefd[prev_pipe], 0);
            close(pipefd[current_pipe]);
        }

        // If current command is the last command, close the
        // write end, else write to the pipe
        if(command_no == n_commands - 1)
        {
            close(pipefd[current_pipe + 1]);
        }
        else
        {
            dup2(pipefd[current_pipe + 1], 1);
        }

        int p = execvp(tokens[cmd_pos[command_no]], tokens + cmd_pos[command_no]);

        close(pipefd[current_pipe]);
        close(pipefd[prev_pipe]);
        close(pipefd[prev_pipe + 1]);
        close(pipefd[current_pipe + 1]);

        _exit(0);
    }
}
int-pipefd[4];
int p1=管道(pipefd);//开放式管道1
int p2=管道(管道FD+2);//开放式管道2
pid_t pid;
对于(i=0;i

如果
/usr/bin
中的程序不是管道中的第一个命令,则它们似乎没有被执行。

您的管道连接不正确

这一逻辑:

int prev_pipe = ((command_no - 1) % 2) * 2;
int current_pipe = (command_no % 2) * 2;
不起作用-模运算的结果总是
0
1
,因此
prev\u pipe
current\u pipe
将是
0
2


好吧,除非我遗漏了一些隐藏的概念,因为您没有粘贴任何创建管道的代码。

下面是一个从您的代码创建的非常简单的程序-猜测如何创建管道,并简化命令
argv
的处理:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static char *argv_ls[] = { "ls", 0 };
static char *argv_wc[] = { "wc", 0 };
static char **cmds[]   = { argv_ls, argv_wc };

int main(void)
{
    int n_commands = 2;
    int pipefd[2];

    pipe(&pipefd[0]);   // Error check!

    fflush(stdout);
    for (int i = 0; i < n_commands; i++)
    {
        int pid = fork();

        if (pid == 0)
        {
            int command_no = i;
            int prev_pipe = ((command_no - 1) % 2) * 2;
            int current_pipe = (command_no % 2) * 2;
            printf("cmd %d: prev pipe %d, curr pipe %d\n", i, prev_pipe, current_pipe);
            fflush(stdout);

            // If current command is the first command, close the
            // read end, else read from the last command's pipe
            if (command_no == 0)
            {
                close(pipefd[0]);
            }
            else
            {
                dup2(pipefd[prev_pipe], 0);
                close(pipefd[current_pipe]);  // Line 40
            }

            // If current command is the last command, close the
            // write end, else write to the pipe
            if (command_no == n_commands - 1)
                close(pipefd[current_pipe + 1]);  // Line 46
            else
                dup2(pipefd[current_pipe + 1], 1);

            execvp(cmds[i][0], cmds[i]);
            fprintf(stderr, "Failed to exec: %s (%d: %s)\n", cmds[i][0], errno, strerror(errno));
            _exit(1);
        }
    }

    return 0;
}
当我运行它时,我会得到输出:

Isis JL: pipes-12133858
cmd 0: prev pipe -2, curr pipe 0
cmd 1: prev pipe 0, curr pipe 2
Isis JL: wc: stdin: read: Bad file descriptor
由于代码中的父级不等待子级完成,因此提示出现在
wc
的错误消息之前,但打印的诊断号显示存在各种问题(并且编译器能够发现一些问题)

请注意,不需要检查任何
exec*()
函数系列的返回值。如果他们成功了,他们就不会回来;如果他们回来,他们就失败了。在调用
\u exit(0)之前也不需要关闭因为系统仍将关闭它们。此外,当您未能执行某项操作时,打印一条消息,指示您未能执行的操作,并以非零退出状态退出是礼貌的

如前所述,问题的一个主要部分是管道处理代码至少是神秘的,因为您没有显示它,而且可能是错误的


我还可以肯定,您的代码中没有足够的
close()
调用。作为指导原则,在每个将成为管道一部分的打开管道的进程中,在任何给定子进程使用
exec*()
函数之前,应该关闭
pipe()
系统调用返回的所有文件描述符。不关闭管道可能会导致进程挂起,因为管道的写入端是打开的。如果写端打开的进程是尝试从管道的读端读取的进程,那么它将找不到任何要读取的数据。

当您尝试从“shell”C程序内部调用此命令时,是否遇到此问题?会发生什么?是的,在C程序中。什么也没发生,
execvp()
不会返回任何错误。您能显示一些代码吗?奇怪。。我想你尝试过其他涉及管道的命令?这些有用吗?如果您自己尝试
ls
,会怎么样?或者如果您执行类似于
cat somefile | wc
的操作。。只是想办法缩小问题的范围。请发布能重现这个问题的最小数量的信息源。就像一个演示这个问题的最小C程序。谢谢。我认为一般的想法是,如果您有N个命令,那么将在单个整数数组中创建N-1个管道:
int pipefd[2*MAX_PIPELINE];对于(int i=0;i我怀疑代码中没有足够的结尾;这是一个常见的麻烦来源。但是,在本例中,应该只有一根管道,这限制了损坏的可能性。通常,当您完成将管道连接到stdin和stdout时,
pipe()
中的文件描述符应该没有打开。正如我所说,它支持多个管道。我已经声明了两个管道
pipefd[0,1]
pipefd[2,3]
,它们将负责通信,无论有多少管道。行
int命令\u no=I
中存在一些问题。您知道如何访问
I
?(不使用共享内存)@green7:有吗?父级和子级中的
i
值相同。在第一次迭代中,
i
的值为0,因此
command\u no
的值为0<代码>(0-1)%2
-1
2*-1
-2
,与打印值相同。等等。也许你不知道负数和正数的模是负数还是零?哦,没错。:)而且,在第一次迭代中,
prev_pipe
的值并不重要,因为有代码检查该命令是否为第一个命令。此外,还有两个管道:
pipefd[0,1]
pipefd[2,3]
。第一个命令写入当前管道+1=1,下一个命令重新写入
Isis JL: pipes-12133858
cmd 0: prev pipe -2, curr pipe 0
cmd 1: prev pipe 0, curr pipe 2
Isis JL: wc: stdin: read: Bad file descriptor