我正在編寫一個模擬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