如果以上所有的絮叨听起来像是创建和使用管道的一种非常迂回的方式,那么还有一种替代方案。
LIBRARY FUNCTION: popen(); PROTOTYPE: FILE *popen ( char *command, char *type); RETURNS: new file stream on success NULL on unsuccessful fork() or pipe() call NOTES: creates a pipe, and performs fork/exec operations using "command"
虽然这个库函数为您执行了相当多的繁琐工作,但也存在着重大的权衡。您失去了曾经通过使用 pipe() 系统调用和自行处理 fork/exec 所拥有的精细控制。然而,由于直接使用了 Bourne shell,shell 元字符扩展(包括通配符)在 "command" 参数中是允许的。
使用 popen() 创建的管道必须使用 pclose() 关闭。到现在为止,您可能已经意识到 popen/pclose 与标准文件流 I/O 函数 fopen() 和 fclose() 惊人地相似。
LIBRARY FUNCTION: pclose(); PROTOTYPE: int pclose( FILE *stream ); RETURNS: exit status of wait4() call -1 if "stream" is not valid, or if wait4() fails NOTES: waits on the pipe process to terminate, then closes the stream.
考虑这个例子,它打开一个到 sort 命令的管道,并继续对一个字符串数组进行排序
/***************************************************************************** Excerpt from "Linux Programmer's Guide - Chapter 6" (C)opyright 1994-1995, Scott Burkett ***************************************************************************** MODULE: popen1.c *****************************************************************************/ #include <stdio.h> #define MAXSTRS 5 int main(void) { int cntr; FILE *pipe_fp; char *strings[MAXSTRS] = { "echo", "bravo", "alpha", "charlie", "delta"}; /* Create one way pipe line with call to popen() */ if (( pipe_fp = popen("sort", "w")) == NULL) { perror("popen"); exit(1); } /* Processing loop */ for(cntr=0; cntr<MAXSTRS; cntr++) { fputs(strings[cntr], pipe_fp); fputc('\n', pipe_fp); } /* Close the pipe */ pclose(pipe_fp); return(0); }
因为popen()使用 shell 来执行其指令,所有 shell 扩展字符和元字符都可供使用!此外,更高级的技术,例如重定向,甚至输出管道,都可以与 一起使用popen(). 考虑以下示例调用
popen("ls ~scottb", "r"); popen("sort > /tmp/foo", "w"); popen("sort | uniq | more", "w");
作为 popen() 的另一个例子,考虑这个小程序,它打开两个管道(一个到 ls 命令,另一个到 sort 命令)
/***************************************************************************** Excerpt from "Linux Programmer's Guide - Chapter 6" (C)opyright 1994-1995, Scott Burkett ***************************************************************************** MODULE: popen2.c *****************************************************************************/ #include <stdio.h> int main(void) { FILE *pipein_fp, *pipeout_fp; char readbuf[80]; /* Create one way pipe line with call to popen() */ if (( pipein_fp = popen("ls", "r")) == NULL) { perror("popen"); exit(1); } /* Create one way pipe line with call to popen() */ if (( pipeout_fp = popen("sort", "w")) == NULL) { perror("popen"); exit(1); } /* Processing loop */ while(fgets(readbuf, 80, pipein_fp)) fputs(readbuf, pipeout_fp); /* Close the pipes */ pclose(pipein_fp); pclose(pipeout_fp); return(0); }
对于我们 popen() 的最后演示,让我们创建一个通用程序,该程序在传递的命令和文件名之间打开一个管道
/***************************************************************************** Excerpt from "Linux Programmer's Guide - Chapter 6" (C)opyright 1994-1995, Scott Burkett ***************************************************************************** MODULE: popen3.c *****************************************************************************/ #include <stdio.h> int main(int argc, char *argv[]) { FILE *pipe_fp, *infile; char readbuf[80]; if( argc != 3) { fprintf(stderr, "USAGE: popen3 [command] [filename]\n"); exit(1); } /* Open up input file */ if (( infile = fopen(argv[2], "rt")) == NULL) { perror("fopen"); exit(1); } /* Create one way pipe line with call to popen() */ if (( pipe_fp = popen(argv[1], "w")) == NULL) { perror("popen"); exit(1); } /* Processing loop */ do { fgets(readbuf, 80, infile); if(feof(infile)) break; fputs(readbuf, pipe_fp); } while(!feof(infile)); fclose(infile); pclose(pipe_fp); return(0); }
尝试运行这个程序,使用以下调用
popen3 sort popen3.c popen3 cat popen3.c popen3 more popen3.c popen3 cat popen3.c | grep main