Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass file names to a subroutine in perl?

I'm writing a perl script and I would like to pass a file name for the output file to a subroutine.

I tried something like this:

use strict;
use warnings;

test("Output.dat");

sub test {
  my $name = @_;

  open(B, ">$name") or die "Failure \n";

  print B "This is a test! \n";
  close(B); 
}

I'm going to use the subroutine multiple times, so i have to pass the file name and cannot declare it within the subroutine.

I hope you can help me :)

like image 653
nieka Avatar asked Dec 20 '22 02:12

nieka


2 Answers

Your problem is this line:

my $name = @_;

You are assigning an array to a scalar variable. In Perl this will give you the number of elements in the array - so I expect you're ending up with "1" in $name.

There are a number of ways to get the first element from an array;

my $name = $_[0]; # Explicitly get the first element
my $name = shift @_; # Get the first element (and remove it from the array)
my $name = shift; # Same as the previous example - shift works on @_ by default in a subroutine
my ($name) = @_; # The parentheses make it into a list assignment

The last two are the ones that you will see most commonly.

A few more points:

1/ You would get a better clue to the problem if you included $name in your error message.

open(A, ">$name") or die "Failure: $name \n";

Or, even better, the error message that Perl gets from your operating system.

open(A, ">$name") or die "Could not open $name: $!\n";

(I've added back the missing comma - I assume that was a typo.)

2/ This days, it is generally accepted as good practice to use the three-arg version of open and lexical filehandles.

open(my $output_fh, '>', $name) or die "Failure: $name \n";

3/ In your example you open a filehandle called "A", but then try to write to a filehandle called "B". Is this a typo?

like image 55
Dave Cross Avatar answered Dec 26 '22 00:12

Dave Cross


my $name = @_;

Will assign to $name value of @_ in scalar mode. It means number of elements in array _. It is a number of arguments. It is most probably not what you would like. So you have to assign an array to an array or a scalar to a scalar. You have two options

my $name = $_[0];

or

my ($name) = @_; # or even (my $name) = @_;

Where I would prefer later because it can be easily modified to my ($a, $b, $c) = @_; and it is Perl idiom.

But your code has more flaws. For example, you should use this open form

open my $fd, '>', $name or die "cannot open > $name: $!";

This has few advantages. The first, you use lexical scoped IO handle which prevents leaking outside of the lexical scope and is automatically closed when exits this lexical scope. The second, list form prevents interpretation of $name content other than file name.

So resulting code should look like:

sub test {
    my ($name) = @_;

    open my $fd, '>', $name
        or die "cannot open > $name: $!";

    print $fd "This is a test!\n";
}
like image 22
Hynek -Pichi- Vychodil Avatar answered Dec 26 '22 00:12

Hynek -Pichi- Vychodil