有很多不同的方法可以做到这一点;使用读取数据可能就足够了fgets()
,然后write()
小心地写入管道:
char line[4096];
while (fgets(line, sizeof(line), stdin) != 0)
{
size_t len = strlen(line);
if (write(pipefd[1], line, len) != len)
{
fprintf(stderr, "Failed to write to pipe\n");
exit(1);
}
}
要模拟管道,您实际上不需要将任何内容从标准输入复制到管道;你可以简单地让rev
读取标准输入。
这是从我对C Minishell 的回答中快速得出的代码——添加满足你需要的管道。
/*
** How to write from stdin to a pipe in C
** https://stackoverflow.com/questions/19826211
**
** Write program pipeline to be invoked as:
**
** pipeline -f outfile2 < infile > outfile1
**
** It should mimic the functionality of the bash script:
**
** (rev | sort | uniq -c | tee outfile2 | wc) < infile > outfile1
**
** Refactored, with equivalent functionality:
**
** rev < infile | sort | uniq -c | tee outfile2 | wc > outfile1
**
** Based on answer to SO 13636252 C Minishell adding pipelines
*/
/* pipeline.c */
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
/* who | awk '{print $1}' | sort | uniq -c | sort -n */
static char *cmd0[] = { "rev", 0 };
static char *cmd1[] = { "sort", 0 };
static char *cmd2[] = { "uniq", "-c", 0 };
static char *cmd3[] = { "tee", 0, 0 };
static char *cmd4[] = { "wc", 0 };
static char **cmds[] = { cmd0, cmd1, cmd2, cmd3, cmd4 };
static int ncmds = sizeof(cmds) / sizeof(cmds[0]);
static char const usestr[] = "[-f filename]";
typedef int Pipe[2];
/* These functions normally declared in stderr.h */
static void err_setarg0(const char *argv0);
static void err_sysexit(char const *fmt, ...);
static void err_syswarn(char const *fmt, ...);
static void err_usage(char const *usestr);
/* exec_nth_command() and exec_pipe_command() are mutually recursive */
static void exec_pipe_command(int ncmds, char ***cmds, Pipe output);
/* With the standard output plumbing sorted, execute Nth command */
static void exec_nth_command(int ncmds, char ***cmds)
{
assert(ncmds >= 1);
if (ncmds > 1)
{
pid_t pid;
Pipe input;
if (pipe(input) != 0)
err_sysexit("Failed to create pipe");
if ((pid = fork()) < 0)
err_sysexit("Failed to fork");
if (pid == 0)
{
/* Child */
exec_pipe_command(ncmds-1, cmds, input);
}
/* Fix standard input to read end of pipe */
dup2(input[0], 0);
close(input[0]);
close(input[1]);
}
execvp(cmds[ncmds-1][0], cmds[ncmds-1]);
err_sysexit("Failed to exec %s", cmds[ncmds-1][0]);
/*NOTREACHED*/
}
/* Given pipe, plumb it to standard output, then execute Nth command */
static void exec_pipe_command(int ncmds, char ***cmds, Pipe output)
{
assert(ncmds >= 1);
/* Fix stdout to write end of pipe */
dup2(output[1], 1);
close(output[0]);
close(output[1]);
exec_nth_command(ncmds, cmds);
}
/* Execute the N commands in the pipeline */
static void exec_pipeline(int ncmds, char ***cmds)
{
assert(ncmds >= 1);
pid_t pid;
if ((pid = fork()) < 0)
err_syswarn("Failed to fork");
if (pid != 0)
return;
exec_nth_command(ncmds, cmds);
}
/* Collect dead children until there are none left */
static void corpse_collector(void)
{
pid_t parent = getpid();
pid_t corpse;
int status;
while ((corpse = waitpid(-1, &status, 0)) != -1)
{
fprintf(stderr, "%d: child %d status 0x%.4X\n",
(int)parent, (int)corpse, status);
}
}
int main(int argc, char **argv)
{
int opt;
char *filename = "outfile2"; // Default file name
err_setarg0(argv[0]);
while ((opt = getopt(argc, argv, "f:")) != -1)
{
switch (opt)
{
case 'f':
filename = optarg;
break;
default:
err_usage(usestr);
break;
}
}
if (optind != argc)
err_usage(usestr);
/* Set the file name for tee to write to */
cmd3[1] = filename;
exec_pipeline(ncmds, cmds);
corpse_collector();
return(0);
}
/* Normally in stderr.c */
static const char *arg0 = "<undefined>";
static void err_setarg0(const char *argv0)
{
arg0 = argv0;
}
static void err_usage(char const *usestr)
{
fprintf(stderr, "Usage: %s %s\n", arg0, usestr);
exit(1);
}
static void err_vsyswarn(char const *fmt, va_list args)
{
int errnum = errno;
fprintf(stderr, "%s:%d: ", arg0, (int)getpid());
vfprintf(stderr, fmt, args);
if (errnum != 0)
fprintf(stderr, " (%d: %s)", errnum, strerror(errnum));
putc('\n', stderr);
}
static void err_syswarn(char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
err_vsyswarn(fmt, args);
va_end(args);
}
static void err_sysexit(char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
err_vsyswarn(fmt, args);
va_end(args);
exit(1);
}
示例输出(outfile1
wheninfile
是程序源代码的副本):
125 691 4879
示例输出(前 10 行和后 10 行outfile2
):
22
1 )... ,tmf* tsnoc rahc(nrawsys_rre diov citats
1 )... ,tmf* tsnoc rahc(tixesys_rre diov citats
1 )0 < ))(krof = dip(( fi
1 )0 < ))(krof = dip(( fi
1 )0 =! )tupni(epip( fi
1 )0 =! dip( fi
1 )0 =! munrre( fi
1 )0 == dip( fi
1 )0vgra* rahc tsnoc(0grates_rre diov citats
...
1 >h.tressa< edulcni#
1 C ni epip a ot nidts morf etirw ot woH **
1 eman elif tluafeD // ;"2eliftuo" = emanelif* rahc
1 senilepip gnidda llehsiniM C 25263631 OS ot rewsna no desaB **
10 {
3 {
2 {
10 }
3 }
2 }
(我注意到无论行是否反转,字数都是相同的,因此该rev
命令在管道中没有任何作用。)有一些诊断输出被捕获;你可以很容易地压制它。