简体   繁体   English

为什么从我的 shell 中的 pipe 获取输入时,execvp() 中的 wc 命令会返回错误的结果?

[英]Why does wc command in execvp() return the wrong results when taking input from a pipe in my shell?

I'm working on writing a shell in C for learning purposes and I'm trying to allow for a variable number of pipes.我正在为学习目的在 C 中编写 shell ,并且我正在尝试允许可变数量的管道。 In general, it seems to work great.一般来说,它似乎工作得很好。 But I noticed a problem with the wc command.但我注意到wc命令有问题。

When I pipe some output of another program into wc like ls | wc当我把另一个程序的 pipe 一些 output 放到wc中时,就像ls | wc ls | wc it always returns ls | wc它总是返回
1 3 35 no matter what I pipe into it. 1 3 35不管我用pipe 进去吧。 Other commands work as expected when I pipe into them.当我 pipe 进入它们时,其他命令按预期工作。 In my normal zsh shell wc works fine.在我正常的zsh shell wc工作正常。 I'm struggling to find the problem.我正在努力寻找问题所在。 I've tried adding waitpid after the forks but no dice.我尝试在分叉后添加waitpid ,但没有骰子。

Here's the main shell loop in the main function:这是主要 function 中的main shell 循环:

while (1) {
        printf("\033[31;1mshell:\033[0m ");

        line = read_cmds();

        if (strstr(line, "|")) {
            // check for pipes first
            pipe_exec(line);
        } else {
            // we have a single command
            tokens = split(line, " \t\r\n");
            if (*tokens != NULL) shell_exec(tokens);
            free(tokens);
        }
    }

Here is the function that loops through the commands:这是循环执行命令的 function:

void pipe_exec(char *line)
{
    int in, status;
    int pipe_no; // keep track of ptr to bring it back to free 
    int pfd[2];
    pid_t rc;
    char **cmd, **pipe_cmds;
    
    // split takes a string and splits into array of strings based on delimiter
    pipe_cmds = split(line, "|"); 

    in = 0;
    pipe_no = 0;
    while (*pipe_cmds) {
        cmd = split(*pipe_cmds, " \t\r\n");

        if (pipe(pfd) < 0) perror("pipe");

        make_proc(in, pfd[1], cmd);
        close(pfd[1]);
        in = pfd[0];
        pipe_cmds++; // move ptr ahead one
        pipe_no++;
    }
    // move pointer back and free
    pipe_cmds -= pipe_no;
    free(pipe_cmds);

    rc = fork();
    if (rc == 0) {
        if (in != 0) dup2(in, STDIN_FILENO);
        execvp(*cmd, cmd);
    } 
}

And then the make_proc function that the above function calls:然后上面的make_proc调用的 make_proc function :

void make_proc(int in, int out, char **cmd)
{
    pid_t rc;
    rc = fork();
    if (rc  == 0) {
        if (in != STDIN_FILENO) {
            dup2(in, STDIN_FILENO);
            close(in);
        }
        if (out != STDOUT_FILENO) {
            dup2(out, STDOUT_FILENO);
            close(out);
        }
        execvp(*cmd, cmd);
    } 
}

I took out some of the error checking to save space here.我在这里取出了一些错误检查以节省空间。 Any help is appreciated!任何帮助表示赞赏!

You execute the last command twice and pipe its first instance to the second.您执行最后一个命令两次,pipe 它的第一个实例到第二个。 Adding something like:添加类似:

    while (*pipe_cmds) { 
        cmd = split(*pipe_cmds, " \t\r\n");
        if (!pipe_cmds[1]) {
            break;
        }

        if (pipe(pfd) < 0) perror("pipe");

        make_proc(in, pfd[1], cmd);
        close(pfd[1]);
        in = pfd[0];
        pipe_cmds++; // move ptr ahead one
        pipe_no++;
    }

would prevent the unnecessary instance, although I would rather have refactored this function a bit.会阻止不必要的实例,尽管我宁愿稍微重构一下这个 function。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM