【发布时间】:2018-09-23 20:50:30
【问题描述】:
我正在尝试在 C 中实现一个 Linux 管道链。例如:
grep file | ls | wc
因此,有一个代码将参数拆分为以管道为分隔符的标记,并将每个部分发送到以下函数,并使用整数指定它是否位于管道之前:
int control_flow(char** args, int precedes){
int stdin_copy = dup(0);
int stdout_copy = dup(1);
// if the command and its args precedes a pipe
if (precedes){
int fd[2];
if (pipe(fd) == -1){
fprintf(stderr, "pipe failed\n");
}
if (dup2(fd[1], 1)!=1)
perror("dup2 error 1 to p_in\n"); // 1 points to pipe's input
status = turtle_execute(args); // executes the argument list, output should go into the pipe
// Code stops running here
if (dup2(fd[0], 0)!=0)
perror("dup2 error 0 to p_out\n"); // 0 points to pipe's output, any process that reads next will read from the pipe
if (dup2(stdout_copy, 1)!=1)
perror("dup2 error 1 to stdout_copy\n"); // 1 points back to stdout
}
// if the command does not precede a pipe
else{
status = turtle_execute(args); // input to this is coming from pipe
if (dup2(stdin_copy, 0)!=0) // 0 points back to stdin
perror("dup2 error 1 to stdin_copy");
}
return 0;
}
我的代码在第一个命令执行后停止运行。我怀疑在使用这个管道之前有必要分叉一个进程,这是为什么呢?如果是这样,我如何在我的代码中做到这一点而不改变我打算做什么?
编辑: 这大致就是turtle_execute 所做的:
turtle_execute(args){
if (args[0] is cd or ls or pwd or echo)
// Implement by calling necessary syscalls
else
// Do fork and exec the process
所以无论我在哪里使用exec,我都首先使用fork,因此替换进程应该不是问题。
【问题讨论】:
-
什么是
turtle_execute? -
@melpomene 它是一个执行参数的函数。如果它是内置的,则编写了一个实现,否则我分叉并执行所需的命令。
-
grep file | ls | wc不是一个明智的管道(假设ls的实现足够标准);ls命令不读取标准输入,因此grep部分不会做任何有用的事情。 -
这里没有足够的代码让任何人都能够解释你如何使用你展示的小代码。您需要创建一个 MCVE (minimal reproducible example)。目前尚不清楚为连接到进程而创建的管道的写入端如何连接到写入进程的标准输出,或者管道的读取端如何连接到管道中下一个进程的标准输入。用内置的命令替换像
ls这样的一大段代码似乎很有趣。我冒昧地猜测您的实现并没有涵盖甚至只是 POSIXls的所有可能性,更不用说 GNU。 -
虽然形式上没有必要 fork 来使用管道,但在少数情况下管道到当前进程是有意义的。您也许可以在多线程进程的两个线程之间使用管道,但这充其量是不合常规的。而且您不会很容易地获得 EOF 指示(对于写入线程或读取线程 - 另一个线程必须关闭其管道末端)。等等。所以,当你使用管道时,你通常会使用 fork;没有什么说你必须分叉(更不用说你必须使用 exec)。