Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 846
Ishpeck Avatar asked Feb 04 '11 19:02

Ishpeck


2 Answers

  1. 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.
  2. 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)

like image 165
Jan Hudec Avatar answered Oct 14 '22 00:10

Jan Hudec


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.)

like image 32
Jim Lewis Avatar answered Oct 14 '22 01:10

Jim Lewis