I want to read STDIN, but at most for 5 seconds. After that I want to process the data I have read so far.
select
seems to be made for exactly that: Wait until there is input or until timeout.
If there is input I should then just read that non-blocking.
So I assumed this would work:
#!/usr/bin/perl -w
use strict;
use Fcntl;
open(my $in, "<&", "STDIN") or die;
my $buf = "";
my $readsize = 10;
# Make $in non-blocking
fcntl($in, &F_SETFL, fcntl($in, &F_GETFL, 0) | &O_NONBLOCK);
while(not eof($in)) {
my $starttime = time();
my $rin = my $win = my $ein = '';
vec($rin, fileno($in), 1) = 1;
while(time() < $starttime + 5 and length $buf < $readsize) {
# Wait up to 5 seconds for input
select($rin, $win, $ein, $starttime + 5 - time());
# Read everything that is available in the inputbuffer
while(read($in,$buf,$readsize,length $buf)) {}
}
print "B:",$buf;
$buf = "";
}
When run like:
(echo block1;sleep 1; echo block1; sleep 6;echo block2)|
perl nonblockstdin.pl
the blocks are merged together. They should have been two blocks because block2 starts 6 seconds later.
What am I doing wrong?
(sleep .1; echo ...
, and will happen if instead ofecho
builtin-in there's some heavyweight external command). That's because perl'seof
will also return true in the case of an error (like theEAGAIN
caused by a read in non-blocking mode). – Dec 29 '19 at 02:38{ sleep .1; echo yup; } | perl -MFcntl -e 'fcntl STDIN, F_SETFL, O_NONBLOCK; warn "EOF!\n" if eof STDIN; sleep 1; print "read after EOF: ", <>'
orperl -e '$SIG{TTIN}="IGNORE"; warn "really?\n" if eof STDIN' &
. – Dec 29 '19 at 02:39