Search code examples
perlunit-testingstdinbuffering

Perl: avoid greedy reading from stdin?


Consider the following perl script (read.pl):

my $line = <STDIN>;
print "Perl read: $line";
print "And here's what cat gets: ", `cat -`;

If this script is executed from the command line, it will get the first line of input, while cat gets everything else until the end of input (^D is pressed).

However, things are different when the input is piped from another process or read from a file:

$ echo "foo\nbar" | ./read.pl
Perl read: foo
And here's what cat gets:

Perl seems to greadily buffer the entire input somewhere, and processes called using backticks or system do no see any of the input.

The problem is that I'd like to unit test a script that mixes <STDIN> and calls to other processes. What would be the best way to do this? Can I turn off input buffering in perl? Or can I spool the data in a way that will "mimic" a terminal?


Solution

  • Today I think I've found what I needed: Perl has a module called Expect which is perfect for such situations:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use Expect;
    
    my $exp = Expect->spawn('./read.pl');
    $exp->send("First Line\n");
    $exp->send("Second Line\n");
    $exp->send("Third Line\n");
    $exp->soft_close();
    

    Works like a charm ;)