How can I tell a Perl function that takes a file to read from the special ARGV handle?
Asked Answered
P

3

7

In perldoc perlvar, I read this:

Note that currently "ARGV" only has its magical effect within the "<>" operator; elsewhere it is just a plain filehandle corresponding to the last file opened by "<>". In particular, passing "*ARGV" as a parameter to a function that expects a filehandle may not cause your function to automatically read the contents of all the files in @ARGV.

So, how can I pass *ARGV (or something that resembles it) as a paramter to a function that expects a filehandle, and have that function read all the files in @ARGV?

Pic answered 29/10, 2010 at 2:46 Comment(0)
R
12

Go right ahead and pass in the *ARGV typeglob or \*ARGV, its reference. Just make sure that the function eventually making use of it does so via the <$fh> operator or readline($fh), its underlying functional equivalent.

The issue addressed in the cited passage from the perlvar manpage is just trying to remind you that you won't be able to get ARGV’s magic open to trigger if you any use other reading mechanism than readline on the handle, such as read, sysread, or getc.

Run this to prove to yourself it works:

sub mycat {
    my $fh = shift;
    print "$ARGV $.: $_" while <$fh>;
}
mycat(*ARGV);

Put that in a file, then run it with several file arguments:

% perl mycat ./mycat //`pwd`/mycat ~/mycat
./mycat 1: sub mycat {
./mycat 2:     my $fh = shift;
./mycat 3:     print "$ARGV $.: $_" while <$fh>;
./mycat 4: } 
./mycat 5: mycat(*ARGV);
///home/tchrist/mycat 6: sub mycat {
///home/tchrist/mycat 7:     my $fh = shift;
///home/tchrist/mycat 8:     print "$ARGV $.: $_" while <$fh>;
///home/tchrist/mycat 9: } 
///home/tchrist/mycat 10: mycat(*ARGV);
/home/tchrist/mycat 11: sub mycat {
/home/tchrist/mycat 12:     my $fh = shift;
/home/tchrist/mycat 13:     print "$ARGV $.: $_" while <$fh>;
/home/tchrist/mycat 14: } 
/home/tchrist/mycat 15: mycat(*ARGV);

See? It works fine.

Rhee answered 29/10, 2010 at 3:37 Comment(0)
T
1

You can redispatch to <> when iterating an overloaded object:

{package ReadARGV;
    sub new {bless []}
    use overload '<>' => sub {<>};
}

sub reader {
    my $fh = shift;
    local $_;
    print while <$fh>;
}

reader(ReadARGV->new);

The ReadARGV package contains a simple object constructor new and then overloads the <HANDLE> operator to simply call <>.

Tuck answered 29/10, 2010 at 3:26 Comment(0)
C
-1

You could fake it with cat (on a Unix system)

open FAKE_ARGV, "cat @ARGV |";
function_expecting_filehandle(*FAKE_ARGV);
...

You lose some of the magic ($ARGV, $.) with this.

I'm sure there's a way to do with a tied filehandle, too (see perltie).

Chatelaine answered 29/10, 2010 at 3:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.