一种想法是模仿标准 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 语言》一书。