首页 > 解决方案 > 如何在我的 shell 中实现管道和重定向?

问题描述

据我所知,有很多关于管道和文件重定向的信息。但我找不到任何关于同时进行管道和文件重定向的具体内容。如果有类似的东西我可能错过了,如果你不介意的话,请给我链接。

我想要做的是在 shell 中执行一个命令,这样就ls -l | grep total > test.txt可以grep从中获取总数ls -l并将其输入test.txt.

我有我的程序设置的方式,一切都被分解成 if() 逻辑来确定使用什么样的符号。这是我只为管道工作的内容,并且只为重定向工作。当我得到 a|和 a时,我对如何继续进行有点困惑>。我怎样才能将两者结合起来?

else if(pipey && !redirect)
{
    char main_str[1024];
    char pipe_str[1024];
    char *left_args[100] = {NULL};
    char *right_args[100] = {NULL};
    strcpy(main_str, string);

    int fd[2];

    char *token = strchr(main_str, '|');
    *token = '\0';
    token++;
    while(*token == ' ')
    {
        token++;
    }

    strcpy(pipe_str, token);

    int i = 0;  
    for(token = strtok(main_str, " \n"), i = 0; token; token = strtok(NULL, " \n" ), ++i)
    {
        left_args[i] = token;
    }

     i = 0;
    for(token = strtok(pipe_str, " \n"), i = 0; token; token = strtok(NULL, " \n" ), ++i)
    {
        right_args[i] = token;
    }

    if(pipe(fd) == -1)
    {
        return 2;
    }

    c1_pid = fork();
    if(c1_pid < 0)
    {
        return 3;
    }

    if(c1_pid == 0)
    {
        dup2(fd[1], STDOUT_FILENO);
        close(fd[0]);
        close(fd[1]);
        execvp(left_args[0], left_args);
    }

    c2_pid = fork();
    if(c2_pid < 0)
    {
        return 4;
    }

    if(c2_pid == 0)
    {
        dup2(fd[0], STDIN_FILENO);
        close(fd[0]);
        close(fd[1]);
        execvp(right_args[0], right_args);

    }

    close(fd[0]);
    close(fd[1]);

    waitpid(c1_pid, NULL, 0);
    waitpid(c2_pid, NULL, 0);

}

// A single redirect given by user
else if(!pipey && redirect)
{
    char main_str[1024];
    char pipe_str[1024];
    char *left_args[100] = {NULL};
    char *middle_args[100] = {NULL};
    char *right_args[100] = {NULL};
    strcpy(main_str, string);

    char *token = strchr(main_str, '>');
    *token = '\0';
    token++;
    while(*token == ' ')
    {
        token++;
    }

    strcpy(pipe_str, token);

    int i = 0;  
    for(token = strtok(main_str, " \n"), i = 0; token; token = strtok(NULL, " \n" ), ++i)
    {
        left_args[i] = token;
    }

     i = 0;
    for(token = strtok(pipe_str, " \n"), i = 0; token; token = strtok(NULL, " \n" ), ++i)
    {
        right_args[i] = token;
    }


    c1_pid = fork();
    if(c1_pid < 0)
    {
        return 5;
    }

    if(c1_pid == 0)
    {
        int file = open(right_args[0], O_WRONLY | O_CREAT, 0777);
        if(file == -1)
        {
            return 6;
        }

        dup2(file, STDOUT_FILENO);
        execvp(left_args[0], left_args);
        close(file);

    }
    waitpid(c1_pid, NULL, 0);
}

再次,只是想知道如何获取我目前拥有的东西,并将其应用于两个符号是否同时出现。所有解析的东西都很好,只是我有点不确定的管道和重复的东西。

标签: cpipeio-redirectiondup

解决方案


将这两个概念分成层次结构:

  1. 首先,管道由一个或多个通过管道链接在一起的命令组成:command | command | command.
  2. 其次,命令由程序、其参数和任何重定向组成:program arg1 arg2 arg3 >redirect1 2>redirect2 <redirect3.

在一个函数中处理管道,在第二个从属函数中处理命令/重定向。

这将让您将这个单一的代码块分解成更小的部分。管道和重定向是正交的概念。它们属于单独的、独立的功能,因此它们不必相互了解。


您还应该将解析与执行分离。智能解耦对于将代码复杂性保持在可管理水平至关重要。

不要解析命令行在同一代码块中执行子进程。将它们分开。执行字符串解析,提取相关部分,然后调用单独的函数来实际 fork/open/dup2/exec/waitpid。


推荐阅读