【问题标题】:Capture stdout to a string and output it back to stdout in C将标准输出捕获为字符串并将其输出回 C 中的标准输出
【发布时间】:2012-06-26 19:20:35
【问题描述】:

使用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输出回原来的stdout?

【问题讨论】:

    标签: c redirect stdout


    【解决方案1】:

    一个想法是模仿标准 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() 中,您需要将测试语句printf("&lt;%c&gt;", c) 替换为write(1, &amp;c, 1)。您可能需要处理对read 的调用中的信号。在两个dup2() 之后,您可能需要添加:

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

    有关此类内容的参考,请参阅 Dave Curry 撰写的 27 岁、220 页的优秀短篇 O'Reilly book 在 Unix 系统上使用 C

    【讨论】:

      【解决方案2】:

      Unix 做到这一点的方法实际上就是编写一个小程序来处理您需要的输入,然后通过命令行将其他程序的输出通过管道传递给它。

      如果你坚持把它全部保存在你的 C 程序中,我会改写那个函数,让它把它的输出发送到给定的字符缓冲区(最好是returning 缓冲区的char *),所以它可以发送到标准输出或根据客户的需要进行处理。

      比如老办法:

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

      ...和新的方式:

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

      【讨论】:

      • 我没有函数的来源,它是从.so调用的
      • @Stasik 你有解决方案吗?我有同样的问题,我运行 ipmitool 来获取一些信息,并想修改内容然后输出到 stdout。我有ipmitool的代码,但是我不想改动太多代码。
      • 我结束了将其包装在脚本中并在那里进行文本处理
      • @Stasik - 我建议在答案中写下来并接受它。我认为粗略回答你自己的问题的时效早已过去,它可能会帮助像查尔斯这样的其他人。
      【解决方案3】:

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

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

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

      【讨论】:

      • 好吧,我已经在 python 中完成了,但我需要将它重新集成回 ANSI C。所以除了调用另一个进程之外别无他法?我不确定,我是否没有在某处违反堆栈高度。
      • 是什么限制您为此使用 C?一种更简洁的方法是通过过滤器管道输出程序的输出,而不是执行所需的更改(假设使用命令行,操作系统支持管道等)。
      • 约束是微控制器上现有的构建和发布系统 + 运行时
      【解决方案4】:
      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-21
        • 1970-01-01
        • 2013-05-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-10
        相关资源
        最近更新 更多