我写了以下代码。它生成一个
grep
,将其输入和输出连接到一些管道,并发送一些文本。然后它尝试读取输出。当我运行它时,我没有看到 grep 的输出。
dup2
(不再重定向 grep 的输出),我会在终端中看到它的输出。cat -
),我会看到预期的输出。我听说有些程序在知道其输出未连接到终端时会以不同的方式缓冲其输出,但是像
echo hello | grep hello | cat
这样的东西如何在命令行上工作呢?控制台是否以某种方式欺骗 grep 认为 cat
是一个终端?
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
struct Pipe
{
int read;
int write;
};
struct Pipe main2grep;
struct Pipe grep2main;
int main()
{
pipe((int*) &main2grep);
pipe((int*) &grep2main);
char *arguments[4];
arguments[0] = "grep";
arguments[1] = "apples";
arguments[2] = 0;
int result = fork();
if (result == 0)
{
dup2(main2grep.read, STDIN_FILENO);
dup2(grep2main.write, STDOUT_FILENO);
execvp(arguments[0], arguments);
return 0;
}
char *input = "apples\n";
int write_result = write(main2grep.write, input, 7);
printf("wrote %d bytes to %s\n", write_result, arguments[0]);
close(main2grep.write);
int pid = result;
char buffer[128];
while (1)
{
int n_read = read(grep2main.read, buffer, 128);
if (n_read != -1)
{
buffer[n_read] = 0;
printf("from grep: %s\n", buffer);
}
}
return 0;
}
我相信发生的事情是,当您运行类似
echo hello | grep hello
之类的内容时,echo
进程结束 - 并且 grep 收到 EOF(更准确地说,grep 调用 read
并返回零字节)。 grep 似乎被编程为在收到 EOF 时自动刷新其输出。
在修改后的代码中,我在 main-to grep 管道的写入端调用
close
。确保从两个进程(父进程和子进程)执行此操作,因为内核仅在所有打开的文件句柄关闭时发送 EOF。当然,在父进程中,您应该只在发送数据后关闭管道。
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
struct Pipe
{
int read;
int write;
};
struct Pipe main2grep;
struct Pipe grep2main;
int main()
{
pipe((int*) &main2grep);
pipe((int*) &grep2main);
char *arguments[4];
arguments[0] = "grep";
arguments[1] = "apples";
arguments[2] = 0;
int result = fork();
if (result == 0)
{
dup2(main2grep.read, STDIN_FILENO);
dup2(grep2main.write, STDOUT_FILENO);
close(main2grep.write);
close(grep2main.read);
execvp(arguments[0], arguments);
return 0;
}
char *input = "apples\n";
int write_result = 0;
write_result += write(main2grep.write, input, 7);
printf("wrote %d bytes to %s\n", write_result, arguments[0]);
close(main2grep.write);
int pid = result;
char buffer[128];
while (1)
{
int n_read = read(grep2main.read, buffer, 128);
if (n_read != -1)
{
buffer[n_read] = 0;
printf("from grep: %s\n", buffer);
}
}
return 0;
}