我正在编写一个模拟Unix管道系统的小程序(例如“cat file1.txt | grep keyword | wc
”)。向stdin写入自制管道系统
我可以设法使用dup2()
和管道从stdout收集程序的输出,但是我无法弄清楚如何将它送到下一个进程。
起初我还以为是简单的,只是这样的:
write(stdin, buffer, buffer_size);
但是这不是为我工作。关于标准输出有很多信息,但没有太多关于标准输入的信息。
任何帮助将是惊人的。
我正在编写一个模拟Unix管道系统的小程序(例如“cat file1.txt | grep keyword | wc
”)。向stdin写入自制管道系统
我可以设法使用dup2()
和管道从stdout收集程序的输出,但是我无法弄清楚如何将它送到下一个进程。
起初我还以为是简单的,只是这样的:
write(stdin, buffer, buffer_size);
但是这不是为我工作。关于标准输出有很多信息,但没有太多关于标准输入的信息。
任何帮助将是惊人的。
你的代码不会做任何阅读或写作;它将只是管道(整理管道)。
您将创建两个管道和两个孩子。第一个孩子将运行命令cat
;第二个命令为grep
,父母将运行wc
程序。由于程序没有路径名,代码将使用execvp()
。
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
static void err_exit(const char *fmt, ...);
static void exec_head(char **args, int *p1, int *p2);
static void exec_tail(char **args, int *p1, int *p2);
static void exec_middle(char **args, int *p1, int *p2);
static void exec_cmd(char **args, int *p1, int *p2);
int main(void)
{
char *cmd1[] = { "cat", "file1.txt", 0 };
char *cmd2[] = { "grep", "keyword", 0 };
char *cmd3[] = { "wc", 0 };
int pipe12[2];
int pipe23[2];
pid_t pid1;
pid_t pid2;
if (pipe(pipe12) != 0 || pipe(pipe23) != 0)
err_exit("Failed to create pipes");
if ((pid1 = fork()) < 0)
err_exit("Failed to fork (child1)");
else if (pid1 == 0)
exec_head(cmd1, pipe12, pipe23);
else if ((pid2 = fork()) < 0)
err_exit("Failed to fork (child2):");
else if (pid2 == 0)
exec_middle(cmd2, pipe12, pipe23);
else
exec_tail(cmd3, pipe12, pipe23);
/*NOTREACHED*/
return(-1);
}
/* Execute head process in pipeline */
/* Close both pipes in p2; connect write end of pipe p1 to stdout */
static void exec_head(char **args, int *p1, int *p2)
{
if (dup2(p1[1], 1) < 0)
err_exit("Failed to duplicate file descriptor to stdout (%s)", args[0]);
exec_cmd(args, p1, p2);
/*NOTREACHED*/
}
/* Execute tail process in pipeline */
/* Close both pipes in p1; connect read end of p2 to standard input */
static void exec_tail(char **args, int *p1, int *p2)
{
if (dup2(p2[0], 0) < 0)
err_exit("Failed to duplicate file descriptor to stdin (%s)", args[0]);
exec_cmd(args, p1, p2);
/*NOTREACHED*/
}
/* Execute middle command in pipeline */
/* Connect read end of p1 to stdin; connect write end of p2 to stdout */
static void exec_middle(char **args, int *p1, int *p2)
{
if (dup2(p1[0], 0) < 0)
err_exit("Failed to duplicate file descriptor to stdin (%s)", args[0]);
if (dup2(p2[1], 1) < 0)
err_exit("Failed to duplicate file descriptor to stdout (%s)", args[0]);
exec_cmd(args, p1, p2);
/*NOTREACHED*/
}
/* Close all descriptors for pipes p1, p2 and exec command */
static void exec_cmd(char **args, int *p1, int *p2)
{
close(p1[0]);
close(p1[1]);
close(p2[0]);
close(p2[1]);
execvp(args[0], args);
err_exit("Failed to execute %s", args[0]);
/*NOTREACHED*/
}
static void err_exit(const char *fmt, ...)
{
int errnum = errno;
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (errnum != 0)
fprintf(stderr, ":%d: %s", errnum, strerror(errnum));
putc('\n', stderr);
exit(EXIT_FAILURE);
}
随着重构更多的工作,并认真处理管道,可以消除exec_head()
,exec_tail()
和exec_middle()
功能(指定描述成为标准输入,或-1,如果它要标准输入独自离开;指定描述符变成标准输出,如果它应该只保留标准输出,则为-1),并且可以通过使用单个数组4来简化管道处理,并相应地将调用修改为pipe()
系统调用。然后就变得很普遍了......代码可能应该使用STDIN_FILENO
和STDOUT_FILENO
而不是0和1作为dup2()
的第二个参数。管道的读写端没有定义的常量(这里可能有用enum { PIPE_READ, PIPE_WRITE };
)。
正如我理解你的问题,你的意思是你想要在你的程序中执行命令cat file1.txt | grep keyword | wc
。
您可以通过在pipe()
与程序之间设置一些管道来实现此目的。 然后fork
几次你想要执行的每个程序。 在不同的分叉过程中,将stdin
和stdout
设置为创建管道的正确结尾。 设置完毕后,您可以拨打exec()
执行不同的程序,如cat
,grep
和wc
,并带有正确的参数。
你的程序只能从wc
程序中读取管道后才能得到最终输出。
你想从标准输入中读取'而不是'写入'它。 – GWW
@GWW吗?但我不想*写入*? 我可能只是努力想象这一点,因为如果我*从输出读*只是假设你*写*到输入... – TrewTzu
在过程之一(即猫)你想写入标准输出,然后在过程两个(即。grep)你想从标准输入读取,然后写入标准输出,最后在进程3(wc)你想从标准输入读取并写入标准输出 – GWW