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

Hello, all:

I'm having trouble with a simple script I'm writing, and would appreciate some help. I have several different workarounds (see Note), but none of them feel "right", so I'm looking for alternatives.

Here's the script I'm having trouble with:

#!/usr/bin/perl # # PM_help.pl FileName - Prints contents of file FileName # PM_help.pl -test - Prints contents of <DATA> handle # PM_help.pl - Prints contents of STDIN # use strict; use warnings; use IO::Handle; # Prepare the selected filehandle my $FName=shift; my $FH = new IO::Handle; if (! defined $FName) { $FH->fdopen(fileno(STDIN), "r") or die "Can't grab STDIN!\nErrMsg: $!\n"; } elsif ($FName eq "-test") { # I was hoping one of these two would work, but no luck #$FH->fdopen(fileno(DATA), "r") # or die "Can't grab DATA!\nErrMsg: $!\n"; #$FH->new_from_fd(fileno(DATA), "r") # or die "Can't grab DATA!\nErrMsg: $!\n"; # Works, but I don't care for it open $FH, '<', $0 or die "Can't open '$0'\nErrMsg: $!\n"; while (<$FH>) { last if /^__DATA__\s*$/; } } else { open $FH, '<', $FName or die "Can't open '$FName'\nErrMsg: $!\n"; } # Use the file... while (<$FH>) { print "$.: $_"; } # EXAMPLE DATA __DATA__ The quick red fox jumped over the lazy brown dog. Now is the time for all good men to come to the aid of their party.

The gist of it is, after reading open, perlopentut and IO::Handle, I can't figure out how to grab the <DATA> handle and put it into $FH as I do with the STDIN handle. While I can do it, I feel that there's a better way.

Why do I care?
I usually keep a set of test data with my scripts so I can easily test them, or use them as example input to refresh my memory when I forget the details. But I don't like having to keep track of the data file along with the script when I move it around, pass it to friends, etc. So I'm trying to adopt the practice of putting the test data in the __DATA__ section at the end of the file. Ultimately, I plan on taking the open logic section and putting it into a subroutine that I can place in my ROBO::Utils module.

Note: I've tried:

However, I can't help but feel that I should be able to redirect the <DATA> filehandle similar to the <STDIN> filehandle, but I just don't know the proper incantation. If no-one can find something better, I'll use what I have.

Thanks in advance!

...roboticus

When your only tool is a hammer, all problems look like your thumb.

Replies are listed 'Best First'.
Re: Filehandle dilemma (DATA, STDIN, a file)
by BrowserUk (Patriarch) on Mar 11, 2011 at 14:18 UTC

    This works:

    #! perl -w use strict; my $fname = shift; my $fh; if( $fname eq '-test' ) { $fh = \*DATA; } elsif( $fname ) { open $fh, '<', $fname or die $!; } else { $fh = \*STDIN; } while( <$fh> ) { print; } __DATA__ my test data

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      BrowserUk:

      Thanks, that's the sort of thing I was hoping to find. I've never really felt comfortable with those globref things, so it never occurred to me to try using one. That prompted me to read perlop and perlref and learn a bit more about them.

      Now I can clean up my latest text munger and move on to the next item on my TODO list.

      ...roboticus

      When your only tool is a hammer, all problems look like your thumb.

        . I've never really felt comfortable with those globref things,

        You're welcome. Now I'm gonna rant, but not at you, so feel free to turn away now :)

        This is a trivial example of why I feel so strongly that the vogue for eschewing whole lumps of Perl's capabilities are self defeating.

        The laudable stated intent is to simplify the learning process for new Perlers. The problem is that each time you omit some subsection of perl's vocabulary from a Perler's education, you end up forcing them to jump through hoops to solve the very problems that subsection of the vocabulary was added to the language to deal with.

        Globrefs: *STDIN, *STDOUT, *STDERR, *DATA, *ARGV, all remain a vital, irreplaceable part of the Perl programmers everyday vocabulary. And sweeping globrefs under the carpet to hide them from newbies does no one any favours. File handles are "global references". The fact that OO-dogma rejects anything "global", and that we can now use lexical aliases to them with some nice to have side effects, doesn't change that.

        Trying to code effectively in Perl without mentioning globrefs is like trying to have everyday conversation without all the words that some would censor with victoriana zeal. Possible, but so stilted as to make it less enjoyable and much harder than it need be.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Filehandle dilemma (DATA, STDIN, a file)
by repellent (Priest) on Mar 12, 2011 at 08:19 UTC
    Be wary about duping filehandles using fileno. It doesn't copy existing PerlIO layers:
    use warnings; use strict; use IO::Handle; use Data::Dumper; local $Data::Dumper::Terse = 1; local $Data::Dumper::Indent = 0; binmode *STDIN, ":encoding(UTF-8)"; my $FH_fileno = IO::Handle->new; $FH_fileno->fdopen(fileno(STDIN), "r") or die $!; my $FH = IO::Handle->new; $FH->fdopen(*STDIN, "r") or die $!; print "*STDIN = ", Dumper([ PerlIO::get_layers(*STDIN) ]), "\n"; print "fdopen fileno = ", Dumper([ PerlIO::get_layers($FH_fileno) ]), +"\n"; print "fdopen STDIN = ", Dumper([ PerlIO::get_layers($FH) ]), "\n"; __END__ *STDIN = ['unix','perlio','encoding(utf-8-strict)','utf8'] fdopen fileno = ['unix','perlio'] fdopen STDIN = ['unix','perlio','encoding(utf-8-strict)','utf8']