使用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输出回原来的标准输出?
答案 0 :(得分: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()
中,您需要使用printf("<%c>", c)
替换测试语句write(1, &c, 1)
。您可能需要在调用read
时处理信号。在两个dup2()
中的每一个之后,您可能想要添加:
close(pipe_fds[0]);
close(pipe_fds[1]);
有关此类内容的参考资料,请参阅Dave的优秀和简短的27页58页O'Reilly book 在Unix系统上使用C 咖喱。
答案 1 :(得分: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;
}
答案 2 :(得分:0)
我真的不喜欢带文件描述符的棘手游戏。你不能修改这个函数,以便除了写入stdout之外还以其他方式返回数据吗?
如果您无法访问源代码,并且您无法访问源代码,那么我建议将写入stdout的代码分解为一个小的单独程序,并将其作为另一个进程运行。从进程重定向输出(可能通过命名管道)是简单而干净的,然后从接收数据的进程输出到stdout就没有问题。
此外,根据您希望进行的编辑类型,最好使用Python等高级语言来编辑数据。
答案 3 :(得分:0)
Python有很好的方法来完成你想要的东西。但是如果你真的需要使用C语言,那么我会用C语言读一些管道。但是要小心,它们可以非常快速地复杂化。
答案 4 :(得分: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