3

我正在尝试更好地了解管道和流程。我想实现多个链式管道,例如cat test.txt | sort | uniq -c. 我用 开始我的代码cat test.txt,但它不起作用。它可以编译,但是当我在命令行中提供文件名时,例如./hwk ./test.txt. 没有任何回报。有人可以看看并给我一些提示吗?我想使用循环,因为我希望能够添加更多管道。我知道我的代码中有很多问题,所以我希望有人能给我一些关于这个主题的指导。谢谢。

#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>

#define SIZE 1024

int main (int argc, char **argv)
{
    int num_pipe = 1;
    int commands = num_pipe + 1; //number of commands is one more than the number of pipes
    int fds[num_pipe * 2];

    int status;
    pid_t pid;
    char *str_ptr;

    //Pass Command
    char *arrayOfCommands[] = {"cat", NULL};


    //Setting up pipes
    int i;
    for (i = 0; i < num_pipe; i++){
        if(pipe(fds + i * 2) == -1) {
            perror("Error creating pipes");
            exit(1);
        }
    }

    int j = 0;
    for (i = 0; i < commands - 1; ++i) {
        pid = fork();

        if (pid == 0) {
            if (i < commands) {
                if (dup2(fds[j+1], 1) < 0) {
                    perror("dup2 error");
                    exit(EXIT_FAILURE);
                }
            }

            if (j != 0) {
                if(dup2(fds[j-2], 0) < 0) {
                    perror("dup2 error");
                    exit(EXIT_FAILURE);
                }
            }

            for (i = 0; i < 2*num_pipe; i++) {
                close(fds[i]);
            }


            if (execvp(arrayOfCommands[0], arrayOfCommands) < 0) {
                perror("Array error");
                exit(EXIT_FAILURE);
            }


        }
        else if (pid < 0){
            perror("Error");
            exit(EXIT_FAILURE);
        }

        j += 2;
    }

    for (i = 0; i < 2 * num_pipe; i++){
        close(fds[i]);
    }

    for (i = 0; i < num_pipe + 1; i++) {
        wait(&status);
    }


    return 0;
}
4

3 回答 3

1

我称这主要是对你的程序的小改编p3.c,编译它来生产p3。由于只cat调用了一个命令(当运行 as 时./p3 p3.c,它会打印出源代码的内容。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>

static void err_exit(const char *str);

int main (int argc, char **argv)
{
    int num_pipe = 0;            // Just cat - no pipes
    int commands = num_pipe + 1; // Number of commands is one more than the number of pipes
    int fds[num_pipe * 2 + 1];   // Avoid size 0 array
    char *arrayOfCommands[3] = { "cat", NULL, NULL};

    if (argc != 2)
        err_exit("Missing filename argument");
    arrayOfCommands[1] = argv[1];

    for (int i = 0; i < num_pipe; i++)
    {
        if (pipe(fds + i * 2) == -1)
            err_exit("Error creating pipes");
    }

    int j = 0;
    for (int i = 0; i < commands; ++i)
    {
        pid_t pid = fork();

        if (pid == 0)
        {
            printf("%d: %s %s\n", (int)getpid(), arrayOfCommands[0], arrayOfCommands[1]);
            fflush(stdout);
            if (i < commands-1 && dup2(fds[j+1], 1) < 0)
                err_exit("dup2 error");
            if (j != 0 && dup2(fds[j-2], 0) < 0)
                err_exit("dup2 error");
            for (i = 0; i < 2*num_pipe; i++)
                close(fds[i]);

            execvp(arrayOfCommands[0], arrayOfCommands);
            err_exit("Array error");
        }
        else if (pid < 0)
            err_exit("Error");

        j += 2;
    }

    for (int i = 0; i < 2 * num_pipe; i++)
        close(fds[i]);

    for (int i = 0; i < num_pipe + 1; i++)
    {
        int status;
        pid_t pid = wait(&status);
        printf("PID %d exited 0x%.4X\n", (int)pid, status);
    }

    return 0;
}

static void err_exit(const char *str)
{
    perror(str);
    exit(EXIT_FAILURE);
}

检查是否适合您。然后你需要弄清楚你将如何创建第二个命令。您arrayOfCommands不会直接提供帮助。您将需要另一个具有某种形状或形式的字符串数组。


运行的扩展cat file | rev。这些变化真的很小。我创建了a_cat用于处理cat命令、a_rev用于rev命令以及a_cmds作为命令数组的命令。也有必要将一个循环固定i到一个循环上k

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>

static void err_exit(const char *str);

int main (int argc, char **argv)
{
    int num_pipe = 1;
    int commands = num_pipe + 1; //number of commands is one more than the number of pipes
    int fds[num_pipe * 2 + 1];   // Avoid size 0 array
    char *a_cat[3] = { "cat", NULL, NULL};
    char *a_rev[2] = { "rev", NULL};
    char **a_cmds[] = { a_cat, a_rev };

    if (argc != 2)
        err_exit("Missing filename argument");
    a_cat[1] = argv[1];

    for (int i = 0; i < num_pipe; i++)
    {
        if (pipe(fds + i * 2) == -1)
            err_exit("Error creating pipes");
    }

    int j = 0;
    for (int i = 0; i < commands; ++i)
    {
        pid_t pid = fork();

        if (pid == 0)
        {
            printf("%d: %s\n", (int)getpid(), a_cmds[i][0]);
            fflush(stdout);
            if (i < commands-1 && dup2(fds[j+1], 1) < 0)
                err_exit("dup2 error");
            if (j != 0 && dup2(fds[j-2], 0) < 0)
                err_exit("dup2 error");
            for (int k = 0; k < 2*num_pipe; k++)
                close(fds[k]);

            execvp(a_cmds[i][0], a_cmds[i]);
            err_exit("Array error");
        }
        else if (pid < 0)
            err_exit("Error");

        j += 2;
    }

    for (int i = 0; i < 2 * num_pipe; i++)
        close(fds[i]);

    for (int i = 0; i < num_pipe + 1; i++)
    {
        int status;
        pid_t pid = wait(&status);
        printf("PID %d exited 0x%.4X\n", (int)pid, status);
    }

    return 0;
}

static void err_exit(const char *str)
{
    perror(str);
    exit(EXIT_FAILURE);
}
于 2013-07-28T04:18:12.937 回答
0

您没有将程序的命令行参数传递给“cat”子进程。你像这样初始化arrayOfCommands-> char *arrayOfCommands[] = {"cat", NULL};<- 然后你把它作为execvp()第二个参数传递给函数。

于 2013-07-28T03:21:52.907 回答
0

好的,您的第一个问题是:

execvp(arrayOfCommands[0], arrayOfCommands);

您正在使用 arrayOfCommands 但我不确定您如何填充 arrayOfCommands 以应对未显示文本文件的情况。我的意思是你在代码前面设置 arrayOfCommands 如下所示:

     char *arrayOfCommands[] = {"cat", "./test.txt", NULL};

如果我理解正确,您的程序称为 hwk,无论出于何种原因,您认为./hwk ./test.txt应该解析,但这意味着您应该解析 argv。

好的,现在已经不碍事了,让我们看看你如何设置的更大问题。

因此,当 shell 解析出管道时,它确实会发生很多事情。考虑以下:

foo fooparam1 fooparam2  | bar  barparam1 | baz bazparam1 bazparam2 

shell 使用递归来解决问题:

foo fooparam1 fooparam2 | ( bar barparam1 | baz bazparam1 bazparam2 )

所以它看起来像:

   spawn_sub_pipes(const char *str) {

           char *cmd =  strtok(str, "|");
           char *rest = strtok(NULL, "|");

           int fds[2]; 
           pipe(fds[]);
           int pid = fork();
           if ( pid < 0 ) {
                 perror("pipe error");
                 exit(-1);
           }

           if ( pid ) { /* parent is the writer */
              close(fds[0]); /* close reading pipe */ 
              dup2(fds[1], 1); /* we attach stdout to the pipe */
           }

           if ( pid == 0 ) {
              close(fds[1]);
              dup2(fds[0], 0); /* attach the pipe to stdin */
              if ( rest ) { /* fork next children */
                  spawn_sub_pipes(rest);
              }
              execvpe(cmd);
           }

   }

重要的提示

我刚刚写了上面的代码,没有测试它。从中获取想法,但不要逐字使用它。

于 2013-07-28T03:27:45.617 回答