Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Help with argument to a subroutine

by unixhome (Novice)
on May 15, 2006 at 18:29 UTC ( [id://549564]=perlquestion: print w/replies, xml ) Need Help??

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

Hello: I am storing (concatenated into) the entire email header into a scalar called $header. Then I am calling a subroutine called parse_header and will be passing the contentns of $header to the sub. The question is hot to refer to the passed arg once the program hits the sub as in the fragment below.
# cat email_header.eml | ./parse_me.pl ################## #!/usr/bin/perl # while (<STDIN>) { .......... $header .= $_; .......... # Passing $header as argument to sub &parse_header($header); .......... } sub parse_header { # How do I refer to the argument ($header) # passed to sub? I want the whole contents # of ($header) to be passed. Is it @_ or $_ while (?????????) do this and that } ##################
Thanks in advance, RV

Replies are listed 'Best First'.
Re: Help with argument to a subroutine
by ikegami (Patriarch) on May 15, 2006 at 18:39 UTC

    All the arguments are in the array @_. In the provided code, the function only has one argument, so it can be referenced as $_[0]. A convenient way of assigning names to your arguments is

    sub parse_header { my ($header) = @_; do this and thia }

    but some people prefer

    sub parse_header { my $header = shift; do this and thia }

    Inside a function, shift with no arguments is the same as shift(@_).

    If you had more than one argument, the above would look as follows:

    sub three_args_func { my ($arg0, $arg1, $arg2) = @_; do this and thia }
    sub three_args_func { my $arg0 = shift; my $arg1 = shift; my $arg2 = shift; do this and thia }

    Reference: perlsub

      Veering OT for a moment...

      Stylistically, I prefer the

      my ($header) = @_;

      method of receiving arguments, but always end up doing it the other way for the sake of being able to specify defaults when not all arguments are passed:

      my $arg0 = shift || 'foo'; my $arg1 = shift || 'bar'; my $arg2 = shift || 'baz';
      Is there a concise way to get this same functionality when using the my ($arg) = @_ method?
        It would be quite ugly:
        my @defaults = qw( foo bar baz ); my ($arg0, $arg1, $arg2) = map { $_[$_] || $defaults[$_] } 0..$#_;
Re: Help with argument to a subroutine
by krisahoch (Deacon) on May 15, 2006 at 18:36 UTC

    unixhome,

    There is more than one way to do it.
    # 1. sub parse_header { # Get the first argument passed to the function/method. my $header = shift(); .... }
    # 2. sub parse_header { # Get the first argument passed to the function/method. my $header = $_[0]; .... }
    Kristofer A. Hoch
    Senior Software Developer (P+++$)
    Aptia Systems, Inc. (http://www.aptia.com)
Re: Help with argument to a subroutine
by shonorio (Hermit) on May 15, 2006 at 18:43 UTC
    I strong recomend you to read POD perlsub, by comand :

    perldoc perlsub
    Where you could see that any arguments passed in show up in the array @_, and you can use shift to get array values.

    Solli Moreira Honorio
    Sao Paulo - Brazil
Re: Help with argument to a subroutine
by Zaxo (Archbishop) on May 15, 2006 at 18:42 UTC

    It is @_, definitely not $_.

    You can refer to a single argument like your $header as $_[0]. If the contents you parse may be delivered in a list,

    sub parse_header { for (@_) { # do this and that to $_, which is set by 'for' } }
    That will work with a single argument, too. Doing it with while would fail if you did not remove elements from @_ as you dealt with them.

    After Compline,
    Zaxo

Re: Help with argument to a subroutine
by GrandFather (Saint) on May 15, 2006 at 18:51 UTC

    Perl passes a list of copies of things to a subroutine in the special array @_.

    There are a couple of things to note here. First off a list is passed, always. It may be empty (@_ == 0) or contain a single item (@_ == 1), but it is still a list and is passed in @_. So the answer to your question is $_[0] or my $headerCopy = shift; (which removes the item from @_), or some similar construct.

    The other thing to notice thought is that Perl passes a copy of the original string. If you wanted to update the original string then you have either to assign a new (returned) version of the string back into the variable ($header = parse_header ($header);) or pass the string by reference (parse_header (\$header);).

    However, in most things Perlish, it pays to let other people do the work. In this case you should take a look at MIME::Tools and MIME::Parser in particular.

    Update: Struck stuff was just plain wrong! @_ contains aliases to the parameters so changing the contents of the elements of @_ changes the matching actual parameter.


    DWIM is Perl's answer to Gödel
Re: Help with argument to a subroutine
by TedPride (Priest) on May 15, 2006 at 19:07 UTC
    while (<STDIN>) { will always return true, since even if the line entered is empty, you will still get a \n from STDIN. So you need a different form of loop. Also, parse_header() needs the entire header passed to it - passing each line one at a time will just make many calls to parse_header(), only the last of which will have the full header.

    What you need is something more like the following (assuming your data is coming in through STDIN - I haven't tested that part):

    use strict; use warnings; my $header; while (1) { chomp($_ = <STDIN>); last if !$_; $header .= "$_\n"; } parse_header($header); sub parse_header { my $header = $_[0]; print $header; ## Do necessary $header processing }

      Or

      while (<STDIN>) { chomp; last if !$_; # or other suitable termination test $header .= "$_\n"; }

      DWIM is Perl's answer to Gödel
      Ted: Sorry about that. I did not put it on my first posting but the first while loop already knows when to execute the sub (when $_ =~ /^$?/). You see, if I run both of those loops independantly from each other (piping the output of one to the second) as in: # cat header.eml | ./first_loop.pl | ./second_loop.pl It works. This is an excersise in Perl programming (with a real purpose...) and I cannot even say (Perl modules) out loud...

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://549564]
Approved by krisahoch
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (7)
As of 2024-04-25 14:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found