문제

I want a Perl module that reads from the special file handle, <STDIN>, and passes this to a subroutine. You will understand what I mean when you see my code. Here is how it was before:

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

use lib '/usr/local/custom_pm'
package Read_FH

sub read_file {
my ($filein) = @_;
open FILEIN, $filein or die "could not open $filein for read\n";
# reads each line of the file text one by one
while(<FILEIN>){
# do something
}
close FILEIN;

Right now the subroutine takes a file name (stored in $filein) as an argument, opens the file with a file handle, and reads each line of the file one by one using the fine handle.

Instead, I want get the file name from <STDIN>, store it inside a variable, then pass this variable into a subroutine as an argument. From the main program:

$file = <STDIN>;
$variable = read_file($file);

The subroutine for the module is below:

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

use lib '/usr/local/custom_pm'
package Read_FH

# subroutine that parses the file
sub read_file {
my ($file)= @_;
# !!! Should I open $file here with a file handle? !!!!

# read each line of the file
while($file){
# do something
}

Does anyone know how I can do this? I appreciate any suggestions.

도움이 되었습니까?

해결책

It is a good idea in general to use lexical filehandlers. That is a lexical variable containing the file handler instead of a bareword.

You can pass it around like any other variables. If you use read_file from File::Slurp you do not need a seperate file handler, it slurps the content into a variable.

As it is also good practice to close opened file handles as soon as possible this should be the preferred way if you realy only need to get the complete file content.

With File::Slurp:

use strict;
use warnings;
use autodie;
use File::Slurp;

sub my_slurp {
    my ($fname) = @_;
    my $content = read_file($fname);

    print $content; # or do something else with $content

    return 1;
}

my $filename = <STDIN>;
my_slurp($filename);

exit 0;

Without extra modules:

use strict;
use warnings;
use autodie;

sub my_handle {
    my ($handle) = @_;
    my $content = '';

    ## slurp mode
    {
        local $/;
        $content = <$handle>
    }

    ## or line wise
    #while (my $line = <$handle>){
    #    $content .= $line;
    #}

    print $content; # or do something else with $content

    return 1;
}

my $filename = <STDIN>;
open my $fh, '<', $filename;
my_handle($fh); # pass the handle around
close $fh;

exit 0;

다른 팁

I agree with @mugen kenichi, his solution is a better way to do it than building your own. It's often a good idea to use stuff the community has tested. Anyway, here are the changes you can make to your own program to make it do what you want.

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

package Read_FH;

sub read_file {
    my $filein = <STDIN>;
    chomp $filein; # Remove the newline at the end
    open my $fh, '<', $filein or die "could not open $filein for read\n";
    # reads each line of the file text one by one
    my $content = '';
    while (<$fh>) {
        # do something
        $content .= $_;
    }
    close $fh;

    return $content;
}

# This part only for illustration
package main;

print Read_FH::read_file();

If I run it, it looks like this:

simbabque@geektour:~/scratch$ cat test
this is a
testfile

with blank lines.
simbabque@geektour:~/scratch$ perl test.pl
test
this is a
testfile

with blank lines.
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top