假设用户在shell say上传递了多个命令
command 1 | command 2 | command 3 | command 4
因此,我编写了一个示例程序,该程序读取char str []内部的命令1 |命令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和pipe,但是我在上面的代码中,当我在while循环内执行命令时,例如while (i < numCommands)
,然后在我想在这里实现什么,因为用户可以在shell上传递的命令数可能是n,所以我该如何实现n个管道,这些管道可以在while循环中用于执行读写操作。更具体地说,我想将一个连接起来命令到管道中的其他命令。
命令行中的多个管道程序用标记“ |”分隔。因此,命令行将具有以下格式:
<program1><arglist1> | <program2><arglist2> | ... | <programN><arglistN> [&]
我在上面的程序中启动了多个进程,但是在正常情况下如何使用管道将它们连接起来,当我知道应该使用多少个管道时,我将构造它们并传递输入。但是这里没有指定用户可以传递多少个命令,因此在这种情况下我该如何实现多个管道。我要寻找的是能够解决我的问题的任何逻辑。
答案 0 :(得分:0)
您需要为每个管道中的另一个管道提供管道对。因此,如果您有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);
}
您可以将其扩展为与两个以上的流程一起使用。