user1607693
user1607693

Reputation: 21

perl process filehandle

I am trying to learn how to read from a process using filehandles. I have tried to write a program that opens a filehandle from the 'date' command and reference that as requested using the following program:

 #!/usr/bin/perl
 use warnings;
 use diagnostics;
 use strict;

 open DATE, 'date|' or die "Cannot pipe from date: $!";
 my $now;

 while (1) {
  print "Press any key: ";
  chomp( my $result=<STDIN> );

  $now = <DATE>;

  print "\$now is: $now\n";

 }   

This works once, or initially, but subsequent 'loops' through the while (1), on the second time around I get an error about 'uninitialized value for $now'. Even stranger, the error goes away after the second loop, but the data from 'date' is never populated into the $now variable.

I presume this may indicate that the filehandle is being closed after the first run through, but I don't know if that is the case or not. I am just now learning perl, I'm sure this is easy and that I just don't have enough experience with the language.

Can anyone provide guidance for me on this? Should I not expect for the DATE filehandle to remain open after the initial run through the loop?

Here is the output from the program at this point:

 $ perl ./test.perl
 Press any key:
 $now is: Fri Aug 17 15:00:27 EDT 2012

 Press any key:
 Use of uninitialized value $now in concatenation (.) or string at ./test.perl
         line 16, <DATE> line 1 (#1)
     (W uninitialized) An undefined value was used as if it were already
     defined.  It was interpreted as a "" or a 0, but maybe it was a mistake.
     To suppress this warning assign a defined value to your variables.

     To help you figure out what was undefined, perl will try to tell you the
     name of the variable (if any) that was undefined. In some cases it cannot
     do this, so it also tells you what operation you used the undefined value
     in.  Note, however, that perl optimizes your program and the operation
     displayed in the warning may not necessarily appear literally in your
     program.  For example, "that $foo" is usually optimized into "that "
     . $foo, and the warning will refer to the concatenation (.) operator,
     even though there is no . in your program.

 $now is:
 Press any key:
 $now is:
 Press any key:
 $now is:
 Press any key:
 $now is:
 Press any key: ^C     

Upvotes: 2

Views: 542

Answers (2)

David W.
David W.

Reputation: 107080

Your program is working as stated. The date command is returning a single line, and you're attempting to read pass the end of file.

The correct way would be:

#! /usr/bin/env perl
use warnings;
use diagnostics;
use strict;
use autodie;
use feature qw(say);

open my $date, "|-", "date";

while (my $now = <$date>) {
   print "Press any key: ";
   chomp( my $result=<STDIN> );

   say "\$now is: $now";
}

And the program will execute a single loop.

A few things:

  • use feature qw(say); allows you to use the say command which is like print except you don't have to keep putting \n at the end.
  • use autodie; automatically allows open statements to die without having to test them. If you're going to die from an open anyway, why not let Perl do it for you.
  • The three parameter open command is preferable. And, also to use scalars for file handles.

What you probably want is something like this:

#! /usr/bin/env perl
use warnings;
use diagnostics;
use strict;
use autodie;
use feature qw(say);

for(;;) {
    print "Press Return to continue...";
    <STDIN>;
    chomp ( my $date = qx(date) );
    say qq(\$date = "$date");
}
  • The qx(...) means quote execute which is preferred over the back quotes.
  • The qq(...) is another way to double quote strings. This allows you to use quotation marks without quoting them with backslashes.

Upvotes: 0

perreal
perreal

Reputation: 98108

You are correct, date only produces a single output and once you read it there is nothing left in the buffer. You can do something like this:

while (1) {
  # ...
  open DATE, 'date|' or die "Cannot pipe from date: $!";
  $now = <DATE>;
  close DATE;
  # ...
  print "\$now is: $now\n";

}   

Another way is to use back tics:

while (1) {
  print "Press any key: ";
  chomp( my $result=<STDIN> );
  print "now is: ".`date`."\n";
 }   

Upvotes: 4

Related Questions