Cygwin reading input piped in from tail -f
Using Cygwin on Windows, I wanted to have an audible notification of specific messages in a server's log. I wrote the following:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *f = fopen("/dev/stdin", "r");
char bar=' ';
if(f==NULL) {
return 1;
}
do {
bar = fgetc(f);
if((bar=='\n') || (bar=='\r')) {
printf("\a");
}
if(bar!=EOF) {
printf("%c", bar);
}
} while(bar!=EOF);
fclose(f);
printf("Done.\n");
return 0;
}
I then ran the following command:
tail -f serverlog | grep myMessage | ./alerty.exe
Sometimes I get notices and sometimes I don't.
My questions are two-fold: 1) What, in 开发者_运维技巧my C program, is wrong? Why can't I consistently read the piped input? It's piqued my curiosity so I'm desperate to know.
2) How do I accomplish the original goal of making my system beep as specific text appears in a file?
- By default stdin/stdout are line-buffered if they are terminal and block-buffered otherwise. That affects not just your program (actually gets will return immediately when something is available and you are printing lines), but also the grep. It needs
--line-buffered
flag. Sed should be able to do the work for you. Try just:
tail -f serverlog | sed -une 's/myMessage/\a&/p'
(
-u
sets unbuffered—hopefuly cygwin supports it—I am checking on Linux)
stdout
is buffered by default, so the output won't necessarily appear immediately. Try inserting a fflush(stdout)
right after your printf("\a")
.
As Jan mentions, you also may be running into buffering issues on stdin. grep
has
a --line-buffered
option that might help. (tail -f
does this on its own, so you shouldn't need to worry about it.)
精彩评论