【问题标题】:how to pipe inside a while loop multiple commands [duplicate]如何在while循环内传递多个命令[重复]
【发布时间】:2019-02-02 03:07:54
【问题描述】:

假设用户在 shell say 上传递了多个命令

command 1 | command 2 | command 3 | command 4

所以我编写了一个示例程序,它在 char str[] 中读取命令 1|command 2(现在为简单起见,我已经对程序中的命令进行了硬编码)

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

int main()
{
  char str[] = "ls -al| grep test.txt"; 


  char *commands[10]; // Array to hold a max of 10 commands
  char *semi = "|";
  char *token = strtok(str, semi);
  int i = 0;
  while (token != NULL)
  {
    commands[i] = token;
    ++i;
    token = strtok(NULL, semi);
  }
  int numCommands = i; // numCommands is the max number of input commands


  i = 0;
  while (i < numCommands)
  {
    printf("Command: %s\n", commands[i]);


    char *args[10] = {}; // Array to hold command args
    args[0] = strtok(commands[i], " ");
    int tokenCounter = 0;
    while (args[tokenCounter] != NULL)
    {
      tokenCounter++;
      args[tokenCounter] = strtok(NULL, " ");
    }


    int childpid = fork();


    if (childpid == 0)
    {
      if ((execvp(args[0], args)) < 0)
      {
        printf("Error! Command not recognized.\n");
      }
    exit(0);
    }

    else if (childpid > 0)
    {
      wait(&childpid);
    }
    else
    {
      printf("Error: Could not create a child process.\n");
      exit(1);
    }

    ++i;
  }

  return 0;
}

我知道在这种情况下我需要使用 dup2 和管道,我也阅读了许多教程,但是在上面的代码中,当我在 while 循环中执行命令时,即 while (i &lt; numCommands),那么这些命令是独立执行的,而我想要在这里实现,因为用户可以在 shell 上传递的命令数量可能是 n 所以我如何实现 n 个管道,我可以在 while 循环中使用这些管道来执行读写。更具体地说,我想将一个命令的输出连接到管道中的其他命令。 命令行中的多个管道程序用标记“|”分隔。因此,命令行将具有以下形式:

 <program1><arglist1> | <program2><arglist2> | ... | <programN><arglistN> [&]

我在上面的程序中启动了多个进程,但是在正常情况下,当我知道应该使用多少个管道时,我如何使用管道连接它们,我会构建它们并传递输入。但是这里的数字并没有指定用户可以传递多少个命令。那么在这种情况下我该如何实现多个管道。任何能够解决我的问题的逻辑都是我正在寻找的。​​p>

【问题讨论】:

  • 你说如果你知道会有多少命令你会知道怎么做,但是你确实知道在进入while循环之前,有多少实际上是。您可以在标记化时或之后计算它们。在最坏的情况下,这意味着您必须进行一些动态分配,而不是依赖自动分配。
  • 是的,正确我没有得到管道的动态分配部分

标签: c pipe posix system-calls execvp


【解决方案1】:

您需要为每个通过管道连接到另一个的程序的管道对。因此,如果您有n 程序,则需要n-1 对管道。

此外,您需要以指定的反向顺序启动这些程序。这样,当执行写入的程序启动时,管道读取端的程序就可以开始读取了。

为简单起见,我们将针对一对命令进行展示:

char *cmd1[] = { "ls", "-l", NULL }; 
char *cmd2[] = { "grep", "test.txt", NULL };
int p[2];

if (pipe(p) == -1) {
    perror("pipe failed");
    exit(1);
}

pid_t p2 = fork();
if (p2 == -1) {
    perror("fork failed");
    exit(1);
} else if (!p2) {
    close(p[1]);
    dup2(p[0], 0);
    execv(cmd1[0], cmd1);
    perror("exec failed");
    exit(1);
}

pid_t p1 = fork();
if (p1 == -1) {
    perror("fork failed");
    exit(1);
} else if (!p1) {
    close(p[0]);
    dup2(p[1], 1);
    execv(cmd2[0], cmd2);
    perror("exec failed");
    exit(1);
}

您可以扩展它以使用两个以上的进程。

【讨论】:

  • OP 声称他的主要困惑在于这个答案所掩盖的部分:如何为两个以上的命令实现这个,此外,确切的数字直到运行时才知道。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-08
  • 1970-01-01
  • 1970-01-01
  • 2014-11-29
  • 2019-02-17
  • 2019-06-24
  • 2016-09-07
相关资源
最近更新 更多