将stdout捕获到字符串并将其输出回C中的stdout

使用C语言。 我有一个写入stdout的函数。

我想捕获该输出,稍微修改它(替换一些字符串)。 然后再将它输出到标准输出。 所以我想从:

char huge_string_buf[MASSIVE_SIZE]; freopen("NUL", "a", stdout); -OR- freopen("/dev/null", "a", stdout); setbuf(stdout, huge_string_buffer); /* modify huge_string_buffer */ 

现在的问题是,如何将huge_string_buffer输出回原始标准输出?

一个想法是模仿标准Unix实用程序tee ,但完全在你的程序中完成,而不依赖于外部重定向。

所以我写了一个简单的函数mytee() ,它似乎有效。 它使用shmget(), pipe(), fork(), and dup2()

 #include  #include  #include  #include  static char *mytee(int size) { int shmid = shmget(IPC_PRIVATE, size + 1, 0660 | IPC_CREAT); int pipe_fds[2]; pipe(pipe_fds); switch (fork()) { case -1: // = error perror("fork"); exit(EXIT_FAILURE); case 0: { // = child char *out = shmat(shmid, 0, 0), c; int i = 0; out[0] = 0; dup2(pipe_fds[0], 0); // redirect pipe to child's stdin setvbuf(stdout, 0, _IONBF, 0); while (read(0, &c, 1) == 1 && i < size) { printf("<%c>", c); // pass parent's stdout to real stdout, out[i++] = c; // and then buffer in mycapture buffer out[i] = 0; // (the extra <> are just for clarity) } _exit(EXIT_SUCCESS); } default: // = parent dup2(pipe_fds[1], 1); // replace stdout with output to child setvbuf(stdout, 0, _IONBF, 0); return shmat(shmid, 0, 0); // return the child's capture buffer } } 

我的测试程序是:

 int main(void) { char *mycapture = mytee(100); // capture first 100 bytes printf("Hello World"); // sample test string sleep(1); fprintf(stderr, "\nCaptured: <%s>\n", mycapture); return 0; } 

输出是:

 < > Captured:  

要在你的应用程序中使用它,在mytee()你需要用write(1, &c, 1)替换测试语句printf("<%c>", c) write(1, &c, 1) 。 并且您可能需要在调用中处理信号以进行read 。 在两个dup2()的每一个之后,你可能想要添加:

  close(pipe_fds[0]); close(pipe_fds[1]); 

有关这类内容的参考,请参阅例如27页的优秀和短期的20页O’Reilly 书,由Dave Curry 在Unix系统上使用C语言

Unix的方法实际上就是编写一个执行所需输入处理的小程序,然后在命令行中将该其他程序的输出传递给它。

如果你坚持要把它全部保存在你的C程序中,那么我要做的就是重写那个函数让它将它的输出发送到给定的char缓冲区(最好是return缓冲区的char * ),以便它可以被发送到stdout或按客户要求处理。

例如,旧的方式:

 void usage () { printf ("usage: frob sourcefile [-options]\n"); } 

……以及新的方式:

 char * usage(char * buffer) { strcpy (buffer, "usage: frob sourcefile [-options]\n"); return buffer; } 

我真的不喜欢带文件描述符的棘手游戏。 你不能修改函数,以便通过写入stdout以其他方式返回其数据吗?

如果您无法访问源代码,并且您无法访问源代码,那么我建议将写入stdout的代码分解为一个小的单独程序,并将其作为另一个进程运行。 从进程重定向输出(可能通过命名管道)是简单而干净的,然后从接收数据的进程输出到stdout就没有问题。

此外,根据您希望进行的编辑类型,最好使用Python等高级语言来编辑数据。

Python有很好的方法来完成你想要的东西。 但是如果你真的需要使用C,那么我会用C语言读一些管道。但要小心,它们可以非常快速地变得非常复杂。

 char huge_string_buf[MASSIVE_SIZE]; FILE stdout_ori=fdopen(stdout,"a"); freopen("NUL", "a", stdout); -OR- freopen("/dev/null", "a", stdout); setbuf(stdout, huge_string_buffer); /* modify huge_string_buffer */ //Write to stdout_fdopen