我目前正致力于编程工作,以在C中实现以下内容:
(rev | sort | uniq -c | tee outfile2 | wc) <simple1.txt> outfile1
我已经看了很多关于这个特定任务的帖子,这个帖子似乎过去很受欢迎。有一个完全充实的解决方案,但根据我们教科书中提供的示例,我对我的方式更感兴趣。我已经成功地将数据传输到tee outfile2
命令并在那里遇到了问题。但是,它似乎不是原子的?我以为数据流经管道应该等待执行直到读取?作为一个例子,我可以在运行时看到以下输出:
./pipeline -f simple1.txt
aa
aa
aa
ab
ac
ac
ac
ba
ba
bb
ca
cb
cb
cc
cc
cc
db
dc
ev
或
18 18 54
All child processes reaped
。
我的代码成功创建了outfile2,但它是空的。第一组或第二组输出应该在文件中,因为输出到终端,因为我在tee的参数中包含了'-'
。我认识到作业的后半部分还没有完成;我一步一步走。
我很感激这方面的帮助。我的代码如下:
/*
* Filename: pipeline.c, read text from stdin to stdout via pipes
* Author: Cody Crawford
* Email: crawfoco@onid.orst.edu
* Course: CS311-400
* Homework: 5
* Citations:
* - TLPI p 900-903
* - Help with pipes, child process, fork, general 'how to' for chaining multiple pipes...
* - My previous code, for getopt() usage
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <getopt.h>
void errExit(char *mystring){
printf("%s\n", mystring);
exit(EXIT_FAILURE);
}
struct command_args{
char out_filename[50];
}mystruct;
struct command_args grab_commands(int argc, char **argv, struct command_args mystruct){
/*
* Grabs command-line arguments. I'm assuming only -f will be passed in with a filename.
*/
char c = getopt(argc, argv, "f");
int end_prog;
if(c == 'f'){
strcat( mystruct.out_filename, argv[2] );
}else{
printf("Error: Unrecognized Input '%c' '%s'\n", c, mystruct.out_filename);
printf("Exiting.\n");
exit(-1);
}
//printf("Received Op: %c && Output File: %s \n", c, mystruct.out_filename);
return mystruct;
}
int main(int argc, char **argv){
struct command_args mystruct;
mystruct = grab_commands(argc, argv, mystruct);
int pfd[2]; /* Pipe file descriptors */
if (pipe(pfd) == -1) /* Create pipe */
errExit("pipe");
/***********************************************************************
* First Child. 'rev' command
***********************************************************************/
switch (fork()) {
case -1:
errExit("fork");
case 0: /* First child: exec 'ls' to write to pipe */
if (close(pfd[0]) == -1) /* Read end is unused */
errExit("close 1");
/* Duplicate stdout on write end of pipe; close duplicated descriptor */
if (pfd[1] != STDOUT_FILENO) { /* Defensive check */
if (dup2(pfd[1], STDOUT_FILENO) == -1)
errExit("dup2 1");
if (close(pfd[1]) == -1)
errExit("close 2");
}
execlp("rev", "rev", mystruct.out_filename, (char *) NULL); /* Writes to pipe */
errExit("execlp rev 1");
default: /* Parent falls through to create next child */
break;
}
/***********************************************************************
* Second Child. 'sort' command
***********************************************************************/
switch (fork()) {
case -1:
errExit("fork");
case 0: /* Second child: exec 'wc' to read from pipe */
if (close(pfd[1]) == -1) /* Write end is unused */
errExit("close 3");
/* Duplicate stdin on read end of pipe; close duplicated descriptor */
if (pfd[0] != STDIN_FILENO) { /* Defensive check */
if (dup2(pfd[0], STDIN_FILENO) == -1)
errExit("dup2 2");
if (close(pfd[0]) == -1)
errExit("close 4");
}
execlp("sort", "sort", (char *) NULL);
errExit("execlp sort 1");
default: /* Parent falls through */
break;
}
/***********************************************************************
* Third Child. 'uniq -c' command
***********************************************************************/
switch (fork()) {
case -1:
errExit("fork");
case 0: /* Second child: exec 'wc' to read from pipe */
if (close(pfd[1]) == -1) /* Write end is unused */
errExit("close 5");
/* Duplicate stdin on read end of pipe; close duplicated descriptor */
if (pfd[0] != STDIN_FILENO) { /* Defensive check */
if (dup2(pfd[0], STDIN_FILENO) == -1)
errExit("dup2 3");
if (close(pfd[0]) == -1)
errExit("close 6");
}
sleep(1);
execlp("uniq", "uniq", "-c", (char *) NULL);
errExit("execlp uniq -c 1");
default: /* Parent falls through */
break;
}
/***********************************************************************
* Fourth Child. 'tee outfile2' command
***********************************************************************/
switch (fork()) {
case -1:
errExit("fork");
case 0: /* Second child: exec 'wc' to read from pipe */
if (close(pfd[1]) == -1) /* Write end is unused */
errExit("close 7");
/* Duplicate stdin on read end of pipe; close duplicated descriptor */
if (pfd[0] != STDIN_FILENO) { /* Defensive check */
if (dup2(pfd[0], STDIN_FILENO) == -1)
errExit("dup2 4");
if (close(pfd[0]) == -1)
errExit("close 8");
}
sleep(5);
execlp("tee", "tee", "outfile2", "-", (char *) NULL);
errExit("execlp tee outfile2 1");
default: /* Parent falls through */
break;
}
/***********************************************************************
* Fifth Child. 'wc' command
***********************************************************************/
switch (fork()) {
case -1:
errExit("fork");
case 0: /* Second child: exec 'wc' to read from pipe */
if (close(pfd[1]) == -1) /* Write end is unused */
errExit("close 9");
/* Duplicate stdin on read end of pipe; close duplicated descriptor */
if (pfd[0] != STDIN_FILENO) { /* Defensive check */
if (dup2(pfd[0], STDIN_FILENO) == -1)
errExit("dup2 5");
if (close(pfd[0]) == -1)
errExit("close 10");
}
execlp("wc", "wc", (char *) NULL);
errExit("execlp wc 1");
default: /* Parent falls through */
break;
}
/* Parent closes unused file descriptors for pipe, and waits for children */
if (close(pfd[0]) == -1)
errExit("close 11");
if (close(pfd[1]) == -1)
errExit("close 12");
while(wait() != -1);
printf("All child processes reaped.\n");
exit(EXIT_SUCCESS);
return;
}
答案 0 :(得分:2)
您只创建了一个管道,但命令行需要四个管道。这意味着第一个之后的命令正在争夺第一个的输出,基本上什么都没有效果。
您需要创建更多管道。你不必预先创建它们,但是你需要密切注意确保它们全部关闭。
此外,您正在实施与声称的管道略有不同的管道:
rev simple1.txt | sort | uniq -c | tee outfile2 | wc
你的程序似乎没有重定向wc
的输出(这没关系; shell非常擅长为你做这个)。
还有另一个:你对getopt()
的使用非常不正统。