C: 无法在不丢失另一个的情况下从 2 个管道文件描述符中读取
C: Cannot read from 2 pipe file descriptors without losing the other one
我有模拟 bash 命令 ls | wc
的 C 代码。我想要实现的一件事是能够读取每个命令的输出,以便我可以打印它们 - ls
和 wc
当 ls
被管道传输时。我面临的这个问题是,每当我阅读其中一个命令时,我都会以某种方式丢失另一个命令。
遵守以下代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#define LS_PATH "/bin/ls"
#define WC_PATH "/usr/bin/wc"
int main()
{
pid_t pid;
int link[2], link2[2];
char *const arg1[] = {"ls", NULL};
char *const arg2[] = {"wc", NULL};
char *buffer1[4096], buffer2[4096];
pipe(link);
pipe(link2);
pid = fork();
if (pid == 0)
{
dup2(link[1], STDOUT_FILENO);
close(link[0]);
close(link[1]);
execv(LS_PATH, arg1);
perror("error1");
}
else
{
pid = fork();
if (pid == 0)
{
dup2(link[0], STDIN_FILENO);
dup2(link2[1], STDOUT_FILENO);
close(link[1]);
close(link[0]);
close(link2[1]);
close(link2[0]);
execv(WC_PATH, arg2);
perror("error2");
}
else
{
close(link[1]);
close(link2[1]);
// the following two lines of code is the point of interest
read(link[0], buffer1, sizeof(buffer1)); // ls
read(link2[0], buffer2, sizeof(buffer2)); // wc
printf("%s\n", buffer1);
printf("%s\n", buffer2);
}
}
}
主要关注以下代码语句:
read(link[0], buffer1, sizeof(buffer1)); // ls
read(link2[0], buffer2, sizeof(buffer2)); // wc
ls
首先被读取到 buffer1
,它打印正常,但是 buffer2
正在读取 wc
只是 returns 0。
如果我要切换上述代码语句的顺序,我将得到以下内容:
read(link2[0], buffer2, sizeof(buffer2)); // wc
read(link[0], buffer1, sizeof(buffer1)); // ls
然后 wc
被读入 buffer2
工作正常,就好像我 运行 终端中的命令 ls | wc
,但是 ls
在 buffer1
不会打印。
我不能两者都得到,只能得到一个或另一个。
如何同时获得两者?
if (pid == 0)
{
dup2(link[0], STDIN_FILENO); // ** HERE **
dup2(link2[1], STDOUT_FILENO);
close(link[1]);
close(link[0]);
close(link2[1]);
close(link2[0]);
execv(WC_PATH, arg2);
perror("error2");
}
请注意 wc
从 link[0]
读取。
// the following two lines of code is the point of interest
read(link[0], buffer1, sizeof(buffer1)); // ls ** HERE **
read(link2[0], buffer2, sizeof(buffer2)); // wc
注意父进程也尝试从 link[0]
.
中读取
您不能同时获得两者,因为写入管道的数据只能从管道中读取一次。如果 wc
读取 ls
的输出来计算它的字符数,那么您不能在父级中也读取 ls
的输出。如果父级从管道中读取 ls
的输出,那么 wc
也无法获取它,因为它不再位于管道中。这就是为什么你只能得到一个或另一个——如果一个东西读取管道,那么它不在管道中供另一个读取。
有很多方法可以解决此问题,具体取决于您的要求。
您可以使用三个管道,额外的管道是 wc
的标准输入。父进程必须将数据从具有 ls
输出的管道复制到作为 wc
输入的管道。
您可以添加第三个进程,一个复制数据的 tee
实例。
您可以ls
写入临时文件。 wc
和您的父进程都可以读取该文件。与管道不同,文件允许多次读取相同的数据。
我有模拟 bash 命令 ls | wc
的 C 代码。我想要实现的一件事是能够读取每个命令的输出,以便我可以打印它们 - ls
和 wc
当 ls
被管道传输时。我面临的这个问题是,每当我阅读其中一个命令时,我都会以某种方式丢失另一个命令。
遵守以下代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#define LS_PATH "/bin/ls"
#define WC_PATH "/usr/bin/wc"
int main()
{
pid_t pid;
int link[2], link2[2];
char *const arg1[] = {"ls", NULL};
char *const arg2[] = {"wc", NULL};
char *buffer1[4096], buffer2[4096];
pipe(link);
pipe(link2);
pid = fork();
if (pid == 0)
{
dup2(link[1], STDOUT_FILENO);
close(link[0]);
close(link[1]);
execv(LS_PATH, arg1);
perror("error1");
}
else
{
pid = fork();
if (pid == 0)
{
dup2(link[0], STDIN_FILENO);
dup2(link2[1], STDOUT_FILENO);
close(link[1]);
close(link[0]);
close(link2[1]);
close(link2[0]);
execv(WC_PATH, arg2);
perror("error2");
}
else
{
close(link[1]);
close(link2[1]);
// the following two lines of code is the point of interest
read(link[0], buffer1, sizeof(buffer1)); // ls
read(link2[0], buffer2, sizeof(buffer2)); // wc
printf("%s\n", buffer1);
printf("%s\n", buffer2);
}
}
}
主要关注以下代码语句:
read(link[0], buffer1, sizeof(buffer1)); // ls
read(link2[0], buffer2, sizeof(buffer2)); // wc
ls
首先被读取到 buffer1
,它打印正常,但是 buffer2
正在读取 wc
只是 returns 0。
如果我要切换上述代码语句的顺序,我将得到以下内容:
read(link2[0], buffer2, sizeof(buffer2)); // wc
read(link[0], buffer1, sizeof(buffer1)); // ls
然后 wc
被读入 buffer2
工作正常,就好像我 运行 终端中的命令 ls | wc
,但是 ls
在 buffer1
不会打印。
我不能两者都得到,只能得到一个或另一个。
如何同时获得两者?
if (pid == 0)
{
dup2(link[0], STDIN_FILENO); // ** HERE **
dup2(link2[1], STDOUT_FILENO);
close(link[1]);
close(link[0]);
close(link2[1]);
close(link2[0]);
execv(WC_PATH, arg2);
perror("error2");
}
请注意 wc
从 link[0]
读取。
// the following two lines of code is the point of interest
read(link[0], buffer1, sizeof(buffer1)); // ls ** HERE **
read(link2[0], buffer2, sizeof(buffer2)); // wc
注意父进程也尝试从 link[0]
.
您不能同时获得两者,因为写入管道的数据只能从管道中读取一次。如果 wc
读取 ls
的输出来计算它的字符数,那么您不能在父级中也读取 ls
的输出。如果父级从管道中读取 ls
的输出,那么 wc
也无法获取它,因为它不再位于管道中。这就是为什么你只能得到一个或另一个——如果一个东西读取管道,那么它不在管道中供另一个读取。
有很多方法可以解决此问题,具体取决于您的要求。
您可以使用三个管道,额外的管道是
wc
的标准输入。父进程必须将数据从具有ls
输出的管道复制到作为wc
输入的管道。您可以添加第三个进程,一个复制数据的
tee
实例。您可以
ls
写入临时文件。wc
和您的父进程都可以读取该文件。与管道不同,文件允许多次读取相同的数据。