c - 在 Linux shell 中实现流水线

标签 c shell

我正在尝试在 Linux 中开发一个 shell 作为操作系统项目。其中一个要求是支持管道(其中调用类似 ls -l|less 的命令将第一个命令的输出传递到第二个命令)。我正在尝试使用 C pipeline() 和 dup2() 命令,但重定向似乎没有发生(更少提示它没有收到文件名)。你能找出我哪里出了问题/我该如何解决这个问题吗?

编辑:我认为我需要在某个地方使用 freopen 或 fdopen,因为我没有使用 read() 或 write()...这是正确的吗?

(我从做过这个项目的其他人那里听说,使用 freopen() 是解决这个问题的另一种方法;如果您认为这更好,那么也将不胜感激。) p>

这是我的execute_external() 函数,它执行shell 中未内置的所有命令。管道中的各种命令(例如[ls -l]和[less])存储在commands[]数组中。

 void execute_external()
{        
    int numCommands = 1;
    char **commands;
    commands = malloc(sizeof(char *));

    if(strstr(raw_command, "|") != NULL)        
    {
        numCommands = separate_pipeline_commands(commands);
    }
    else
    {
        commands[0] = malloc(strlen(raw_command) * sizeof(char));
        commands[0] = raw_command;
    }

    int i;
    int pipefd[2];
    for (i = 0; i < numCommands; i++)
    {
        char **parameters_array = malloc(strlen(commands[i]) * sizeof(char *));
        int num_params;
        num_params = str_to_str_array(commands[i], parameters_array);

        if (numCommands > 1 && i > 0 && i != numCommands - 1)
        {
            if (pipe(pipefd) == -1)
            {
                printf("Could not open a pipe.");
            }
        }

        pid_t pid = fork();


        pmesg(2, "Process forked. ID = %i. \n", pid);
        int status;
        if (fork < 0)
        {
            fprintf(to_write_to, "Could not fork a process to complete the external command.\n");
            exit(EXIT_FAILURE);
        }

        if (pid == 0) // This is the child process
        {
            if (numCommands > 1) { close(pipefd[1]); } // close the unused write end of the pipe
                           if (i == 0) // we may be pipelining and this is the first process
            {
                dup2(1, pipefd[1]); // set the source descriptor (for the next iteration of the loop) to this proc's stdout
            }
            if (i !=0 && (i != numCommands-1)) // we are pipelining and this is not the first or last process
            {
                dup2(pipefd[0], 0); // set the stdin of this process to the source of the previous process
            }
            if (execvp(parameters_array[0], parameters_array) < 0)
            {
                fprintf(to_write_to, "Could not execute the external command. errno: %i.\n", errno);
                exit(EXIT_FAILURE);
            }
            else    { pmesg(2, "Executed the child process.\n");}
        }
        else
        {
            if (numCommands > 1) { close(pipefd[0]); } // close the unused read end of the pipe
            if (backgrounding == 0) { while(wait(&status) != pid); }// Wait for the child to finish executing
        } 
        free(parameters_array);
    }
free(commands);
    }

最佳答案

您的代码中似乎存在一些错误。

首先,你所有的 dup2 都只在子进程中。为了连接管道,您需要将父级的 stdout dup2 到管道的写入端 pipelinefd[1] 。然后你将读取端连接到标准输入。

而且看起来你的 dup2 中的一个是向后的,dup2 fildes 被复制到 fildes2。因此,当您重新分配标准输入时,您需要 dup2(in, 0),对于标准输出,您需要 dup2(out, 1)。

因此,一段精简的管道代码将如下所示:

 int pipefd[2];
 pipe(pipefd);

 pid_t pid = fork();

 if (pid == 0) //The child
 {
      dup2(pipefd[0], 0);
 }
 else
 {
      dup2(pipefd[1], 1);
 }

关于c - 在 Linux shell 中实现流水线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5037697/

相关文章:

linux - 如何在 Linux Bash 脚本文件中使用 'sed' 来注释掉带有制表符间距的特定行?

linux - Shell 脚本 - 意外 token `then'

shell - ksh - 检查字符串是否有模式

c++ - 强制结构大小为 8 字节

c - 可以使用 execvp 和 fork 退出和更改目录的简单 Shell

c - 在 Qt Creator 中运行纯 C 项目

bash - Shell 相等运算符(=、==、-eq)

作为选项传递时,shell 波浪号扩展不起作用

c - 简单C程序中的总线错误

c - 在 C 函数中使用 | 进行查询参数中的运算符