2

使用C语言。我有一个写入标准输出的函数。

我想捕获该输出,对其进行一些修改(替换一些字符串)。然后再次将其输出到标准输出。所以我想开始:

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 输出回原始标准输出?

4

4 回答 4

2

一种想法是模仿标准 Unix 实用程序的功能tee,但完全在您的程序中这样做,而不依赖于外部重定向。

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

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/shm.h>

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;
}

输出是:

<H><e><l><l><o>< ><W><o><r><l><d>
Captured: <Hello World>

要在您的应用程序中使用它,mytee()您需要将 test 语句替换printf("<%c>", c)write(1, &c, 1). 并且您可能需要在对 . 的调用中处理信号read。在这两个之后dup2(),您可能需要添加:

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

有关此类内容的参考资料,请参阅Dave Curry撰写的 27 年历史的 220 页 O'Reilly 的《在 Unix 系统上使用 C 语言》一书。

于 2012-06-27T00:31:42.840 回答
1

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;
}
于 2012-06-26T19:34:00.973 回答
0

我真的不喜欢带有文件描述符的棘手游戏。您不能修改该函数,以便它以其他方式返回其数据,而不是写入标准输出?

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

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

于 2012-06-26T19:25:02.747 回答
0
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
于 2012-06-26T19:34:09.527 回答