Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Perl, how do I process input as soon as it arrives, instead of waiting for newline?

Tags:

perl

I'd like to run a subcommand from Perl (or pipe it into a Perl script) and have the script process the command's output immediately, rather than waiting for a timeout, a newline, or a certain number of blocks. For example, let's say I want to surround each chunk of input with square brackets. When I run the script like this:

$ ( echo -n foo ; sleep 5 ; echo -n bar ; sleep 5; echo baz) | my_script.pl

I'd like the output to be this, with each line appearing five seconds after the previous one:

[foo]
[bar]
[baz]

How do I do that?

This works, but is really ugly:

#! /usr/bin/perl -w

use strict;
use Fcntl;

my $flags = '';
fcntl(STDIN, F_GETFL, $flags);
$flags |= O_NONBLOCK;
fcntl(STDIN, F_SETFL, $flags);

my $rin = '';
vec($rin,fileno(STDIN),1) = 1;
my $rout;

while (1) {
  select($rout=$rin, undef, undef, undef);
  last if eof();

  my $buffer = '';

  while (my $c = getc()) {
    $buffer .= $c;
  }

  print "[$buffer]\n";
}

Is there a more elegant way to do it?

like image 571
raldi Avatar asked Oct 17 '08 21:10

raldi


People also ask

What does Stdin mean in Perl?

In Perl programming, we can get input from standard console using <STDIN>. It stands for Standard Input. It can be abbreviated by <>.

How do I print the next line in Perl?

The Perl print function\n"; Notice that you need to supply the newline character at the end of your string. If you don't supply that newline character, and print multiple lines, they'll all end up on one long line of output, like this: Hello, world.

How do I use echo in Perl?

The backticks ( ` ) run the shell command and give you the output. So the echo is running inside of a shell and in this case it just returns the one shell variable. A cleaner way to get this in Perl is to use %ENV like so: my $jobID = $ENV{'JOBID'};

How do I input a Perl script?

Input to a Perl program can be given by keyboard with the use of <STDIN>. Here, STDIN stands for Standard Input . Though there is no need to put STDIN in between the 'diamond' or 'spaceship' operator i.e, <>. It is standard practice to do so.


2 Answers

From perlfaq5: How can I read a single character from a file? From the keyboard?. You probably also want to read How can I tell whether there's a character waiting on a filehandle?. Poll the filehandle. If there is a character there, read it and reset a timer. If there is not character there, try again. If you've retried and passed a certain time, process the input.

After you read the characters, it's up to you to decide what to do with them. With all the flexibility of reading single characters comes the extra work of handling them.

like image 156
brian d foy Avatar answered Nov 14 '22 21:11

brian d foy


Term::ReadKey can do this for you. In particular setting the ReadKey() mode to do the polling for you.

use Term::ReadKey;

$| = 1;
while( my $key = ReadKey(10) ) {
    print $key;
}
like image 38
Schwern Avatar answered Nov 14 '22 23:11

Schwern