CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
Using Arguments with Subroutines

 



griever92
Novice

Oct 30, 2012, 7:23 PM

Post #1 of 14 (2405 views)
Using Arguments with Subroutines Can't Post

I've been running into some issue with one of my scripts now that i've been breaking it into smaller chunks and calling for them using subroutines.

Primarily, when it comes to passing arguments from the command line, to the main script, to the subroutine, and then return a value back out into the main script block.

I've pulled out the problem area and made a demo set of files to hopefully explain what i'm trying to do.

main.pl

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

require '/home/griever92/bin/TESTING_MODEL/testarg/sub.pl';

my $arg = $#ARGV;
my $target = '';

print "\n\nArguement is $arg \n";

&callback;

print "\n $target \n";


sub.pl

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

sub callback {
my $main_arg = @_;
my $target = '';
if ($main_arg == -1) {
exit 0;
}
$target = $_[0];

print "\n\n $target \n";

}
1;


running this via...
perl main.pl this.is.a.test.string
produces these results:

Code
Arguement is 0 
Use of uninitialized value $target in concatenation (.) or string at /home/griever92/bin/btnup/TESTING_MODEL/testarg/sub.pl line 13.


The first print statement is returning a 0, instead of my string, not only that though, the subroutine seemingly receives nothing, and does nothing as well.


If I put this same sort of setup into a single file...
full.pl

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

my $numArgs = $#ARGV;
my $target = '';
if ($numArgs == -1) {
exit 0;
}
foreach $numArgs ($#ARGV) {
$target = $ARGV[$numArgs];
}

print "\n\n $target \n\n"


I receive the following output.

Code
this.is.a.test.string


Obviously, this is what I want to be seeing returned inside the subroutine for certain operations contained within, as well as being able to use this resultant variable later in the main script block.
Unfortunately, I can't seem to get my head around this.


(This post was edited by griever92 on Oct 31, 2012, 5:54 AM)


Laurent_R
Veteran / Moderator

Oct 31, 2012, 12:24 AM

Post #2 of 14 (2382 views)
Re: [griever92] Using Arguments with Subroutines [In reply to] Can't Post


Code
my $main_arg = @_;


This is wrong. @_ is an array, $main_arg a scalar.


rovf
Veteran

Oct 31, 2012, 2:48 AM

Post #3 of 14 (2379 views)
Re: [griever92] Using Arguments with Subroutines [In reply to] Can't Post

In addition to what Laurent_R said:

You don't pass any argument to your sub, hence $target is undef.


Laurent_R
Veteran / Moderator

Oct 31, 2012, 5:29 AM

Post #4 of 14 (2377 views)
Re: [rovf] Using Arguments with Subroutines [In reply to] Can't Post

Example of argument passing:


Code
# main 

my ($x, $y) = (1, 2);

($x, $y) = switch_subroutine ($x, $y);
# now $x is 2 and $y = 1

sub switch_subroutine {
my ($local_x, $local_y) = @_;
return ($local_y, $local_x);
}



griever92
Novice

Oct 31, 2012, 5:52 AM

Post #5 of 14 (2375 views)
Re: [Laurent_R] Using Arguments with Subroutines [In reply to] Can't Post

If possible i'd like to avoid an array, the reason I have it currently setup in that method in my test case is because that seems to be the only thing I can find using google.

This also shows passing an argument that is hard-coded into the script, i'm looking for something that deals with the command line itself (script is called via perl main.pl [-switches] [ARG/FileName/DirName])
Ideally, there will only ever be 1 argument after the switches, but i'll likely be adding in error handling to trim all but the final argument.

Is there anyway you could demonstrate this using the code I have posted above?
Like I said, I can't seem to get my head around the issue, i've probably spent a good week on Google trying to implement this is various methods i've seen suggested, but no luck so far.


Laurent_R
Veteran / Moderator

Oct 31, 2012, 6:05 AM

Post #6 of 14 (2373 views)
Re: [griever92] Using Arguments with Subroutines [In reply to] Can't Post

If you are in the main routine, and assuming there is only one argument passed to the script, you could do:


Code
my $target = shift;


or


Code
my $target = $ARGV[0];


or


Code
my ($target)= @ARGV;



griever92
Novice

Oct 31, 2012, 6:39 AM

Post #7 of 14 (2370 views)
Re: [Laurent_R] Using Arguments with Subroutines [In reply to] Can't Post

So if i'm understanding this correctly, I will need to define the argument into a variable, prior to passing said variable to a subroutine, yes?

Is my problem simply that I have been trying to pass the CLI argument directly to the sub, without referencing it in the main?


FishMonger
Veteran / Moderator

Oct 31, 2012, 6:40 AM

Post #8 of 14 (2370 views)
Re: [griever92] Using Arguments with Subroutines [In reply to] Can't Post

Getopt::Long - Extended processing of command line options
http://search.cpan.org/~jv/Getopt-Long-2.38/lib/Getopt/Long.pm


griever92
Novice

Oct 31, 2012, 6:41 AM

Post #9 of 14 (2368 views)
Re: [FishMonger] Using Arguments with Subroutines [In reply to] Can't Post


In Reply To
Getopt::Long - Extended processing of command line options
http://search.cpan.org/~jv/Getopt-Long-2.38/lib/Getopt/Long.pm


I have the options setup in my actual script, they are working.
I'm having trouble with the ARG that comes afterwards.


FishMonger
Veteran / Moderator

Oct 31, 2012, 6:42 AM

Post #10 of 14 (2367 views)
Re: [griever92] Using Arguments with Subroutines [In reply to] Can't Post


Quote
Is my problem simply that I have been trying to pass the CLI argument directly to the sub, without referencing it in the main?



Code
callback( shift );



FishMonger
Veteran / Moderator

Oct 31, 2012, 6:43 AM

Post #11 of 14 (2365 views)
Re: [griever92] Using Arguments with Subroutines [In reply to] Can't Post

What are the exact program specs that your instructor gave you?


griever92
Novice

Oct 31, 2012, 7:30 AM

Post #12 of 14 (2362 views)
Re: [FishMonger] Using Arguments with Subroutines [In reply to] Can't Post

No instructor involved, this is my own project that i'm working on, so there's no real specs, I just need something that works.

Essentially what i'm doing in the main script is handling of the switches, while subroutines handle the bulk of the other work.

The switches that I call with the script, determine which subroutines are (or are not) run.

I have 2 subroutines near the opening that essentially serve the same purpose, but produce a different end result. This is where i'm running into trouble, as these subroutines are set to handle the argument which is meant to be passed from the command line.

=====

Below, is an excerpt from the primary script block, however I have modified the variable/sub names.
$switch1 and $switch2 are both defined earlier in the code block, and are activated by means of a switch via CLI.
In this example, let's assume $switch2 is activated by 'l'.

main.pl ||| perl main.pl -l this.is.my.target

Code
if ($switch1) { 
&sub1
}
elsif ($switch2) {
&sub2( shift );
}


This would drive the script to perform &sub2

sub2.pl

Code
sub sub2 
{
my $numArgs = $#ARGV;
my $show_dir = '';
if ($numArgs == -1) {
print "Need Target Parameter\n";
exit 0;
}
foreach $numArgs ($#ARGV) {
$show_dir = $ARGV[$numArgs];
}

there's a bunch of other stuff below this excerpt, but it appears to be working.

at this point, $show_dir should equal 'this.is.my.target' and should be useable from the main script block.


(This post was edited by griever92 on Oct 31, 2012, 7:37 AM)


FishMonger
Veteran / Moderator

Oct 31, 2012, 8:08 AM

Post #13 of 14 (2352 views)
Re: [griever92] Using Arguments with Subroutines [In reply to] Can't Post

Show us your code that parses the switches. That's where your problem is located.

Actually, you should show us your entire script.

Normally I'd have more error handling, but here's a minimal script showing one way how to use the module to process the switches.


Code
#!/usr/bin/perl 

use 5.10.0;
use strict;
use warnings;
use Getopt::Long;

GetOptions(
'l=s' => \&my_sub( @ARGV ),
);


sub my_sub {
shift;
die "Need Target Parameter\n" unless @_;
print shift;;
}


Outputs:

Quote
c:\testing>main.pl -l this.is.my.target
this.is.my.target



(This post was edited by FishMonger on Oct 31, 2012, 8:08 AM)


Laurent_R
Veteran / Moderator

Nov 1, 2012, 2:39 AM

Post #14 of 14 (2333 views)
Re: [griever92] Using Arguments with Subroutines [In reply to] Can't Post


In Reply To
So if i'm understanding this correctly, I will need to define the argument into a variable, prior to passing said variable to a subroutine, yes?

Is my problem simply that I have been trying to pass the CLI argument directly to the sub, without referencing it in the main?


You don't have to, but it will often be clearer if you do, especially if you give sensible names to your variables.

But you have the right to write in the main section of your program:


Code
my $foo = some_function($ARGV[0], $ARGV[2]);


or even:

Code
my $bar = some_other_function(@ARGV);


It is however usually clearer to state what the arguments are by storing them in appropriately named variables:


Code
my ($width, $length) = @ARGV; 

my ($perimeter, $area) = compute_rectangle($width, $length);


And the function definition:


Code
sub compute_rectangle { 
my ($local_w, $local_l) = @_;
my $local_perim = 2 * ($local_w + $local_l);
my $local_area = $local_w * $local_l;
return ($local_perim, $local_area);
}


(I would normally not call my variables $local_w, $local_l, etc., but I wanted to insist here that they are local copies of $width, $length, etc., available only within the function. I am not even sure I would write a function for such easy calculations, unless the same function were used somewhere else in the program.)

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives