Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assign STDIN to variable in strict mode

Tags:

perl

strict

The following code works quite as intended when using no strict:

my $file = STDIN;
while (<$file>) {
    print "$_\n";
}

How would be an equal solution using use strict;?


I've tried so far: ${STDIN}, $STDIN, \$STDIN, <STDIN>, and \STDIN, and I am aware that the last two operators (<> and \) have different meanings than I want to use here.

What kind of variable is STDIN anyway? Is it considered a scalar?

like image 451
Manuel Faux Avatar asked Dec 14 '22 15:12

Manuel Faux


2 Answers

my $stdin_h = \*STDIN;

provides the fewest surprises. That is a globref.

See also perldoc perlref and Typeglobs and Filehandles in perldata:

Another use for typeglobs is to pass filehandles into a function or to create new filehandles. If you need to use a typeglob to save away a filehandle, do it this way:

$fh = *STDOUT;

or perhaps as a real reference, like this:

$fh = \*STDOUT;

STDIN is a bareword. When the argument to a function expecting a file handle, it's equivalent to one of the above \*STDIN, but it's equivalent to "STDIN" the rest of the time (for which use strict 'refs'; throws an error).

Perl documentation I linked to explains the differences between the various data types involved, but DavidW's brief summary is useful:

*STDIN is a type glob. This has to do with how Perl stores info in its symbol table. Perl creates an entry in it's symbol table for a particular name, and then creates hash entries for subroutines, file handles, hashes, arrays, and scalars with those names. You can reference this symbol table entry with a * sigil and it's called a type glob. The problem is that there is no sigil for file handles, so you have to refer to them with the type glob. When you open FH ..., FH is a file handle. When you use open my $fh ..., $fh is a type glob ref.

like image 150
Sinan Ünür Avatar answered Dec 22 '22 00:12

Sinan Ünür


Sinan Ünür has a way of actually getting the file handle into a variable and is mentioned in the Perl documentation.

However, it involves deep dark Perl mysteries which may be confusing for many developers who aren't familiar with these secrets. You have to know to look in perldata and look in the very last section, and that's if you figure out what Typeglobs are.

There is another way that's less mysterious and easier to understand:

use strict;
use warnings;
use feature qw(say);
use autodie;        #  Doesn't work. You need to verify 

use IO::File;
...

my $file = IO::File->new;
$file->fdopen( fileno( STDIN ), 'r')
     or die qq(<STDIN> is not opened.);
while ( my $entry = <$file> ) {
    chomp $entry;
    say qw(The entry is "$entry");
}

Okay, this isn't exactly crystal clear either, but it does have an advantage that you know where to look for the documentation. fileno is a function, so that's easy to look up (Returns the file descriptor for a filehandle, or undefined if the filehandle is not open.).

And since fdopen is a method of IO::File, you know you can find information about that in the IO::File Perldoc.

Okay, I lied, the documentation for fdopen is actually in the IO::Handle Perldoc. But, the IO::File Perldoc does say that it inherits its methods from IO::Handle. Once you do figure out to look in IO::Handle, you see an example of this very code right in the synopsis.

like image 45
David W. Avatar answered Dec 21 '22 22:12

David W.