bofh_of_oz has asked for the wisdom of the Perl Monks concerning the following question:

Venerable monks,

I am writing a script to process syslog messages passed to it. Syslog-ng takes care of filtering the messages so that only the valid ones will be sent to the program/script. The problem is, syslog will start the script only once, and will send messages to the <STDIN> of the script as they arrive.

What I need is to read <STDIN>, clear it (make it empty), and check it again later.

I know I can read <STDIN> with $line = <STDIN>; What I don't know is how to empty <STDIN> after that and how long to wait before reading it again (I don't want to read <STDIN> when syslog is in the middle of sending the message)

Any advice/pointers are appreciated.

--------------------------------
An idea is not responsible for the people who believe in it...

Replies are listed 'Best First'.
Re: Need to empty STDIN
by 5mi11er (Deacon) on May 20, 2005 at 15:40 UTC
    select is your friend, read about it here. Specifically you're looking at the multi-io option with a timeout field.

    The idea is to read STDIN when there is data available, and otherwise to sleep for a bit, then check select to see if there is more data, sleep, etc.

    -Scott

Re: Need to empty STDIN
by zentara (Cardinal) on May 20, 2005 at 15:42 UTC
    It sounds like you want to add STDIN to IO::Select. When STDIN is readable, it will run the callback which will read everything it can. I didn't write the following, fellow monk edan did, but I'll post it in case he is out golfing or something. :-)
    #!/usr/bin/perl use warnings; use strict; use IO::Select; # by edan of perlmonks # I just remembered what select says about mixing # buffered reading and "select", so even though the # code works, you might want to substitute # the read via <$fh> with: # my $input; # sysread( $fh, $input, 1024); # loop every 1 second my $timeout = 1; my $s = IO::Select->new(); $s->add( \*STDIN ); while (1) { if ( my @ready = $s->can_read($timeout) ) { # we got input for my $fh (@ready) { my $input = <$fh>; print "got: $input"; } } else { # no input } # just to show that we're looping print scalar localtime; }

    I'm not really a human, but I play one on earth. flash japh
      I'm not sure if the fact that I'm on Windows changes anything, but this script:
      - does not run *every second* => it runs continuously (I mean, I get LOTS of output messages per second)
      - does not read STDIN - whatever I type, is processed by the OS after the script is terminated.

      --------------------------------
      An idea is not responsible for the people who believe in it...

        on Windows

        My condolences. :-)


        I'm not really a human, but I play one on earth. flash japh
Re: Need to empty STDIN
by polettix (Vicar) on May 20, 2005 at 17:07 UTC
    Maybe I'm reading your post in the wrong way, but you don't need anything more than reading from STDIN.
    What I don't know is how to empty <STDIN> after that
    Each read removes the data you read from STDIN, if you want to empty it just keep reading
    and how long to wait before reading it again
    You don't have to explicitly wait, if there's data your read will succeed, if there isn't your read will block gracefully until they arrive
    I don't want to read <STDIN> when syslog is in the middle of sending the message
    This is not a problem at all (I hope). Note that the idiom:
    $line = <STDIN>
    reads until end-of-file (which shouldn't happen in your case, unless you have major problems) or until it hits the end of the record separator $/, which is normally set to a newline to give you one line at a time.

    So, if you analyse your logs on a line-oriented fashion, you don't have to do anything. OTOH, if you have to correlate different lines, you have to implement some logic to understand when and where you want to break your input into parts. Anyway, this doesn't seem a problem related to STDIN IMHO.

    Hope this helps to fade away your fears.

    Flavio (perl -e 'print(scalar(reverse("\nti.xittelop\@oivalf")))')

    Don't fool yourself.
      Thanks a lot!
      That really helped. Now I'll just finish and test the whole script... and hope it works the way I intend :)

      --------------------------------
      An idea is not responsible for the people who believe in it...