10

Is there any way to clear the STDIN buffer in Perl? A part of my program has lengthy output (enough time for someone to enter a few characters) and after that output I ask for input, but if characters were entered during the output, they are "tacked on" to whatever is entered at the input part. Here is an example of my problem:

for(my $n = 0; $n < 70000; $n++){
   print $n . "\n";
}
chomp(my $input = <STDIN>);
print $input . "\n";

The output would include any characters entered during the output from that for loop. How could I either disable STDIN or flush the STDIN buffer (or any other way to not allow extra characters to be inserted into STDIN before calling it)?

mcwillig
  • 213
  • 3
  • 9
  • Ok, I have been looking for an answer to this question for 3 days now (not every hour of every day, but I would say at least 3 or 4 hours per day) and have not yet found an answer, in fact I asked my colleagues, who also know and use Perl, and they do not know either, so I do believe that I have put in more effort than you are implying that have I put in, that aside, do you have any idea as to how to do what I am asking? Because I already looked through your link, about 3 days ago, tried implementing those functions in a way that would logically fix this issue, and it did not work. – mcwillig Sep 29 '11 at 20:30
  • 1
    `use IO::Handle;STDIN->autoflush(1);` –  Sep 29 '11 at 20:48
  • Thank you for your answer, but, this didn't fix the problem, also, I do remember reading autoflush and flush are only good for output, such as STDERR and STDOUT, not input. When I tried what you suggested, I still get the characters I entered during the output of the for loop plus what ever I entered in at STDIN. – mcwillig Sep 29 '11 at 21:07
  • 4
    @JackManey: Generally, "flushing" applies to output, not input. – Keith Thompson Sep 29 '11 at 21:32

3 Answers3

13

It looks like you can accomplish this with the Term::ReadKey module:

#!perl

use strict;
use warnings;
use 5.010;

use Term::ReadKey;

say "I'm starting to sleep...";
ReadMode 2;
sleep(10);
ReadMode 3;
my $key;
while( defined( $key = ReadKey(-1) ) ) {}
ReadMode 0;
say "Enter something:";
chomp( my $input = <STDIN> );
say "You entered '$input'";

Here's what happens:

  • ReadMode 2 means "put the input mode into regular mode but turn off echo". This means that any keyboard banging that the user does while you're in your computationally-expensive code won't get echoed to the screen. It still gets entered into STDIN's buffer though, so...
  • ReadMode 3 turns STDIN into cbreak mode, meaning STDIN kind of gets flushed after every keypress. That's why...
  • while(defined($key = ReadKey(-1))) {} happens. This is flushing out the characters that the user entered during the computationally-expensive code. Then...
  • ReadMode 0 resets STDIN, and you can read from STDIN as if the user hadn't banged on the keyboard.

When I run this code and bang on the keyboard during the sleep(10), then enter some other text after the prompt, it only prints out the text I typed after the prompt appeared.

Strictly speaking the ReadMode 2 isn't needed, but I put it there so the screen doesn't get cluttered up with text when the user bangs on the keyboard.

CanSpice
  • 34,814
  • 10
  • 72
  • 86
0

I had the same problem and solved it by just discarding anything in STDIN after the processing like this:

for(my $n = 0; $n < 70000; $n++){
  print $n . "\n";
}
my $foo=<STDIN>;
print "would you like to continue [y/n]: ";
chomp(my $input = <STDIN>);
print $input . "\n";
  • -- just realized this only works if there is a return during processing, otherwise it will pause until someone hits enter – Sy Bernot Aug 26 '16 at 16:20
-4
{ local $/; <STDIN> }

This temporarily - limited to scope of the block - sets $/, the input record seperator, to be undef, which tells perl to just read everything instead of reading a line at a time. Then reads everything available on STDIN and doesn't do anything with it, thus flushing the buffer.

After that, you can read STDIN as normal.

DrHyde
  • 1,546
  • 1
  • 14
  • 14
  • 2
    This won't work. The `` call blocks until a "record" can be read. But if `$/` is `undef`, there can be no end of the record, so it will block until EOF is reached. – mob Sep 29 '11 at 23:02