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

I have a command-line script that generates output intermittently. It may display a few lines, run for a couple of minutes, display a couple hundred lines, run for a couple more minutes, etc. The user needs to be able to reliably review all of the output as it is generated.

I thought, "no problem, I'll just pipe it to the more command" to enable pagination, like so:

unless (open(MORE, " | more")) { die("ERROR! Cannot fork a process to \"more\" command\n"); } print MORE "whatever\n";

But there are several problems with this. The main one is that "more" initially will not display anything until it has a full page of text to display. Several minutes could pass with nothing appearing on the screen, even though it may have output to display. In fact, if the script has little output to display, it could be quite a few minutes until the script finishes and all of the output is finally displayed on one page.

I thought that there surely must be a command-line switch to tell "more" (or "less") not to buffer the first page, but if there is, I can't find it. I've tried various workarounds without success and I'm stumped.

Another annoying side-effect of "more" is that if the user happens to press the space bar one or more times before the "--More--" prompt has appeared, it buffers the keys and processes them later, potentially spewing several pages of output without the user noticing it. I thought that there surely must be a way of preventing this "type ahead" problem, but my search for a fix to this has been fruitless, as well.

So is there a simple way to implement reliable paging in Perl without these side-effects?

Replies are listed 'Best First'.
Re: Simple Way to Paginate Output?
by almut (Canon) on Jul 12, 2010 at 19:56 UTC
    I thought that there surely must be a command-line switch to tell "more" (or "less") not to buffer the first page,

    It's not more that's buffering, it's your script writing to it — non-interactive output (the pipe here) is block-buffered by default.  Try adding

    use IO::Handle; ... MORE->autoflush(); ...

    Also, a quick CPAN search found IO::Page and IO::Pager.

      Thank you so much!! The autoflush on the pipe is what I needed.

      The other annoying thing is the way that you can type ahead when more-ing. Is there a simple way to prevent this? I seem to recall years ago writing a command-line script that would clear the key input buffer before waiting for more input, but for the life of me I can't figure out what that trick was.

Re: Simple Way to Paginate Output?
by bobdog (Initiate) on Jul 14, 2010 at 21:27 UTC

    I'm happy to say that I've figured out how to clear the keyboard buffer and prevent the annoying type-ahead:

    use Term::ReadKey; ... clear_keys(); print MORE $message; ... sub clear_keys { while (my $key = ReadKey(-1)) { } }
Re: Simple Way to Paginate Output?
by aquarium (Curate) on Jul 13, 2010 at 06:38 UTC
    tail -f the_growing_file | more
    or
    process_keeps_writing_stdout | tailf -f | more
    the hardest line to type correctly is: stty erase ^H