accessing arrays in a different sub-routine

Discussion in 'Perl Misc' started by erik, Mar 28, 2005.

  1. erik

    erik Guest

    I tried to find the answer on the web, camel book, and did not know
    which perldoc to look in(perlop did not have it). I also tried a few
    different things to make it work, any nothing has worked.

    I dynamically create an array from an expect output. I want to then
    print it out in a different array. I research references private vs.
    global scalars and did not find my answer. This is my code:

    #!/usr/bin/perl
    #################################################################
    # Global Variables #
    #################################################################
    use warnings;
    use Expect;
    use CGI(":standard");
    $Expect::Log_Stdout = 0;
    $device = param("device");
    $username = param("username");
    $password = param("password");
    $enable = "enable";
    $save = "wr mem";
    $enable_password = param("enable_password");
    $service_type = param("service_type");
    my $datetemp = `date +%x_%r`;
    my @dateStamp = split('\n',$datetemp);
    my @bandwidth_array;
    my $bandwidth_array;
    (SNIP)
    ##################################################################
    # Now we check for bandwidth statement #
    ###################################################################
    sub bandwidth_router_check{
    $timeout ="15";
    my $bandwidth = "The router has at least 1 bandwidth statement";
    my $no_bandwidth = "The router is missing a bandwidth statement";
    $command->clear_accum();
    print $command "show config \| inc band\r";
    unless ($command->expect($timeout, -re, '#')) {
    return "Never got telnet prompt".$command->exp_error()."\n";
    }
    my $bandwidth_capture = $command->exp_before();
    my @bandwidth_array = split ('\n', $bandwidth_capture);

    #HERE WE CHECK LOGGING

    if ($bandwidth_capture =~ /band.*/)
    {
    push (@band_tests, $bandwidth);
    $band_action = "OK";
    }
    else{
    push (@band_tests, $no_bandwidth);
    $band_action = "FAIL";
    }

    print "bandwidth_array 1 is $bandwidth_array[1]\n"; #THIS PRINT WORKS
    GREAT!

    };#end sub


    Then I call it in a different sub-routine.

    ################################################################### #
    Prints the main parameters that should be in ALL routers #
    ###################################################################
    sub print_main_report
    {
    my @bandwidth_array;
    my $bandwidth_array;

    print "Content-type: text/html\n\n";
    print "<html><head><title>QA REPORT</title></head>";
    print "<body bgcolor=#000000>";
    print "<p align=center><b><font color=#FFFFFF size=5>ROUTER QA
    REPORT</font></b></p>";
    print "<br>";
    print "<p align=center><font color=#FFFFFF><b>Date: $dateStamp[0]
    EST<b></font></p>";
    print "<br>";
    print "<body><font color=#FFFFFF><b>QA Report for:
    $device<b></font></body>";
    print "<br>";

    print "<br>";
    #we print for bandwidth
    if ($band_action eq "OK")
    {
    print "<body><font
    color=33CC33>@band_tests.............$band_action</font></body>";
    }
    else{
    print "<body><font
    color=FF0000>@band_tests.............$band_action</font></body>";
    }
    print "<br>";
    print "<body>bandwidth_array 1 is $bandwidth_array[1]</body>";
    #THIS DOES NOT PRINT AN ELEMENT, IT PRINT AN EMPTY ELEMENT.
    print "<br>";
    }

    Can anyone give me some input? I tried to may the refences to it global
    instead of scoped, but that did not do it. How should this sort of
    thing be done?
    erik, Mar 28, 2005
    #1
    1. Advertising

  2. erik

    erik Guest

    I dynamically create an array from an expect output. I want to then
    print it out in a different array. I research references private vs.
    global scalars and did not find my answer. This is my code:

    I had a typo here, should read:

    I dynamically create an array from an expect output. I want to then
    print it out in a different sub-routine. I research references private
    vs.
    global scalars and did not find my answer. This is my code:
    erik, Mar 28, 2005
    #2
    1. Advertising

  3. erik

    Paul Lalli Guest

    erik wrote:
    > I tried to find the answer on the web, camel book, and did not know
    > which perldoc to look in(perlop did not have it). I also tried a few
    > different things to make it work, any nothing has worked.
    >
    > I dynamically create an array from an expect output. I want to then
    > print it out in a different array.


    This is non-sensical. Arrays do not print anything.

    > I research references private vs.
    > global scalars and did not find my answer.


    I don't think you researched enough.

    > This is my code:
    > #!/usr/bin/perl
    > #################################################################
    > # Global Variables #
    > #################################################################
    > use warnings;


    You are forgetting "use strict;"

    > use Expect;
    > use CGI(":standard");
    > $Expect::Log_Stdout = 0;


    > $device = param("device");
    > $username = param("username");
    > $password = param("password");
    > $enable = "enable";
    > $save = "wr mem";
    > $enable_password = param("enable_password");
    > $service_type = param("service_type");


    There is no reason to make any of these package variables. They should
    all be declared with 'my'

    > my $datetemp = `date +%x_%r`;
    > my @dateStamp = split('\n',$datetemp);
    > my @bandwidth_array;


    This variable, having been declared lexical outside of any subroutine,
    will be accessable anywhere below its declaration.

    > my $bandwidth_array;


    That's a remarkably poor choice of a variable name. For one, you
    already have an array named "bandwidth_array". (Just because Perl
    allows this doesn't make it a good idea). For two, this isn't an array,
    it's a scalar.


    > (SNIP)
    > ##################################################################
    > # Now we check for bandwidth statement #
    > ###################################################################
    > sub bandwidth_router_check{
    > $timeout ="15";
    > my $bandwidth = "The router has at least 1 bandwidth statement";
    > my $no_bandwidth = "The router is missing a bandwidth statement";
    > $command->clear_accum();
    > print $command "show config \| inc band\r";
    > unless ($command->expect($timeout, -re, '#')) {
    > return "Never got telnet prompt".$command->exp_error()."\n";
    > }
    > my $bandwidth_capture = $command->exp_before();
    > my @bandwidth_array = split ('\n', $bandwidth_capture);


    You are declaring a new lexical array. This array will be valid for the
    duration of this subroutine, and will then disappear. For the remainder
    of this subroutine, this new variable masks the existing lexical you
    decalred above.

    >
    > #HERE WE CHECK LOGGING
    >
    > if ($bandwidth_capture =~ /band.*/)
    > {
    > push (@band_tests, $bandwidth);
    > $band_action = "OK";
    > }
    > else{
    > push (@band_tests, $no_bandwidth);
    > $band_action = "FAIL";
    > }
    >
    > print "bandwidth_array 1 is $bandwidth_array[1]\n"; #THIS PRINT WORKS
    > GREAT!


    Of course it does. You're printing the second element of the variable
    you just declared in this subroutine.

    >
    > };#end sub
    >
    >
    > Then I call it in a different sub-routine.
    >
    > ################################################################### #
    > Prints the main parameters that should be in ALL routers #
    > ###################################################################
    > sub print_main_report
    > {
    > my @bandwidth_array;


    Now here's another entirely new lexical. This one again masks the first
    one you declared, and is valid for the duration of this subroutine. It
    has absolutely nothing whatsoever to do with either the variable you
    declared in the previous subroutine, or with the variable you declared
    at the top of the file.

    > my $bandwidth_array;


    <snip>

    > print "<body>bandwidth_array 1 is $bandwidth_array[1]</body>";
    > #THIS DOES NOT PRINT AN ELEMENT, IT PRINT AN EMPTY ELEMENT.


    Of course it does. You're trying to print the second element of an array
    you never added anything to.

    > print "<br>";
    > }
    >
    > Can anyone give me some input? I tried to may the refences to it global
    > instead of scoped, but that did not do it. How should this sort of
    > thing be done?


    You generally have two options:
    1) Make a variable that is lexically scoped to the entire file. You put
    one declaration near the top of the file, just as you did here. You
    then simply *use* that variable. Don't declare any more variables of
    the same name.
    2) Have the function that first sets the variable declare the variable
    lexically scoped to the function itself, and then pass that variable (or
    at least its value) around using array parameters and function return
    values.


    You should probably read "Coping with Scoping", which talks about the
    different scopes of variables.
    http://perl.plover.com/FAQs/Namespaces.html


    Paul Lalli
    Paul Lalli, Mar 28, 2005
    #3
  4. "erik" <> wrote in news:1112037688.658680.167210
    @g14g2000cwa.googlegroups.com:

    > my $datetemp = `date +%x_%r`;


    In addition to Paul Lalli's excellent commnents elsethread, let me please
    ask, WHY?

    No need to spawn an external program to just a get a timestamp.

    perldoc -f time
    perldoc -f localtime

    > my @dateStamp = split('\n',$datetemp);


    perldoc -f chomp

    See also the strftime function in the POSIX module.

    The only reason you declare and use @dateStamp is to get rid of the EOL at
    the end of $datetemp. You might think the above is harmless, but puzzling
    gems like this make your programs hard to read later.

    Sinan
    A. Sinan Unur, Mar 28, 2005
    #4
  5. erik

    erik Guest

    I just read that, thanks. That sheds some light. So basically with my
    example above, and due to it's dynamic nature, the only way I can get
    this working is a sub-function within a subfunction. I really didn't
    want to do that, but I take it I have no choice. I thought I could do
    my $bandwidth_array; in my printing sub-routine but like you said, it
    in't DOING anything.

    I liked this line from the coping with scope.

    When to Use my and When to Use local
    Always use my; never use local.

    Wasn't that easy?

    BTW, what was wrong with the name that I gave my array
    @bandwidth_array? You lost me on that one.
    erik, Mar 28, 2005
    #5
  6. "erik" <> wrote in news:1112049496.433969.94040
    @g14g2000cwa.googlegroups.com:

    > I just read that, thanks.


    Please quote an appropriate amount of context when replying.

    > That sheds some light. So basically with my
    > example above, and due to it's dynamic nature, the only way I can get
    > this working is a sub-function within a subfunction. I really didn't
    > want to do that, but I take it I have no choice.


    You lost me here.

    Here is a simple example of what you can do:

    #! /usr/bin/perl

    my $files = read_files_in_current_dir();

    $files or die "No files in current directory\n";

    my_print($files);

    sub read_files_in_current_dir {
    opendir my $dir, '.'
    or die "Cannot open current directory: $!";
    [ grep { -f } readdir $dir ];
    }

    sub my_print {
    print "$_\n" for sort @{ shift() };
    }

    __END__

    The first subroutine you call generates the array you want, and returns
    a reference to it. Then, you pass that reference to other subroutines
    that work on the array.

    No need for nested subroutines.

    > BTW, what was wrong with the name that I gave my array
    > @bandwidth_array? You lost me on that one.


    For me, the '@' in front of the name already signifies that the variable
    is an array, why replicate that information?

    Sinan
    A. Sinan Unur, Mar 29, 2005
    #6
  7. erik

    Ala Qumsieh Guest

    A. Sinan Unur wrote:

    > "erik" <> wrote in news:1112049496.433969.94040
    > @g14g2000cwa.googlegroups.com:


    >>BTW, what was wrong with the name that I gave my array
    >>@bandwidth_array? You lost me on that one.

    >
    >
    > For me, the '@' in front of the name already signifies that the variable
    > is an array, why replicate that information?


    Actually, Paul was commenting on this:

    >> my $bandwidth_array;


    This is a scalar, not an array (note the leading '$' sigil). Having the
    name of a scalar end in '_array' can lead to confusion.

    --Ala
    Ala Qumsieh, Mar 29, 2005
    #7
  8. erik

    Paul Lalli Guest

    I wrote, but erik didn't quote:
    > You generally have two options:
    > 1) Make a variable that is lexically scoped to the entire file. You
    > put one declaration near the top of the file, just as you did here.
    > You then simply *use* that variable. Don't declare any more variables
    > of the same name.
    > 2) Have the function that first sets the variable declare the variable
    > lexically scoped to the function itself, and then pass that variable
    > (or at least its value) around using array parameters and function
    > return values.


    erik wrote:
    > I just read that, thanks. That sheds some light. So basically with my
    > example above, and due to it's dynamic nature, the only way I can get
    > this working is a sub-function within a subfunction. I really didn't
    > want to do that, but I take it I have no choice.


    How does anything I said above translate to this? I said nothing about
    nested subroutines. I simply said to not re-declare your variable
    within the subroutine. Just use the variable you already have:

    my $foo;
    sub fctn1{
    $foo = 1;
    }
    sub fctn2{
    print "Foo = $foo\n";
    }

    fctn1(); #$foo gets set here
    fctn2(); #$foo gets printed here.

    Your problem is that you had additional "my $foo;" statements within
    fctn1 and fctn2. Get rid of them.

    > BTW, what was wrong with the name that I gave my array
    > @bandwidth_array? You lost me on that one.


    Well, if you'd bother quoting what was said:

    erik wrote:
    > my $bandwidth_array;

    I replied:
    > That's a remarkably poor choice of a variable name. For one, you
    > already have an array named "bandwidth_array". (Just because Perl
    > allows this doesn't make it a good idea). For two, this isn't an
    > array, it's a scalar.


    you'd see that I did not say @bandwidth_array is a poor name. I said
    that $bandwidth_array is a poor name. Those are two wholly unrelated
    variables. They have nothing to do with one another. Naming the same
    name implies that they do. Plus, naming a scalar variable
    "something_array" is just a bad idea, I hope for obvious reasons.

    Out of curiousity, have you read the posting guidelines for this group yet?

    Paul Lalli
    Paul Lalli, Mar 29, 2005
    #8
  9. erik

    erik Guest

    No I haven't read the guidelines. I just looked and did not see them.
    Would you mind posting the link and I will be glad to play nice in the
    sandbox.
    erik, Apr 2, 2005
    #9
  10. "erik" <> wrote in news:1112404124.313308.95980
    @g14g2000cwa.googlegroups.com:

    > No I haven't read the guidelines. I just looked and did not see them.


    They are posted here regularly. In fact, a fresh copy was posted today.

    > Would you mind posting the link and I will be glad to play nice in the
    > sandbox.


    Would you mind typing

    comp.lang.perl.misc posting guidelines

    in that Google search box?

    Sinan

    --
    A. Sinan Unur <>
    (reverse each component and remove .invalid for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
    A. Sinan Unur, Apr 2, 2005
    #10
  11. erik

    Joe Smith Guest

    erik wrote:
    > I just read that, thanks. That sheds some light. So basically with my
    > example above, and due to it's dynamic nature, the only way I can get
    > this working is a sub-function within a subfunction.


    No, not at all.

    Use 'my' or 'our' to declare variables.
    Do not re-declare an already declared variable.

    This does not work:

    my @array; # File scoped (global) variable
    sub set_it {
    my @array = (1,2,3); # A new, different variable
    }
    sub print_it {
    my @array; # Yet another different variable
    print "@array";
    }
    set_it; print_it;

    But if you get rid of the 2nd and 3rd 'my', it will work.

    Better yet, use 'our' instead of 'my':

    sub set_it {
    our @array; # Lexical access to long-lived variable
    @array = (1,2,3);
    }
    sub print_it {
    our @array; # Access to same long-lived variable
    }
    set_it; print_it;




    > I liked this line from the coping with scope.
    >
    > When to Use my and When to Use local
    > Always use my; never use local.


    I say "Always use my or our; never use local unless forced to."

    -Joe
    Joe Smith, Apr 3, 2005
    #11
  12. Joe Smith wrote:

    > erik wrote:
    >
    >> I just read that, thanks. That sheds some light. So basically with my
    >> example above, and due to it's dynamic nature, the only way I can get
    >> this working is a sub-function within a subfunction.

    >
    > Use 'my' or 'our' to declare variables.
    > Do not re-declare an already declared variable.
    >
    > This does not work:
    >
    > my @array; # File scoped (global) variable
    > sub set_it {
    > my @array = (1,2,3); # A new, different variable
    > }
    > sub print_it {
    > my @array; # Yet another different variable
    > print "@array";
    > }
    > set_it; print_it;
    >
    > But if you get rid of the 2nd and 3rd 'my', it will work.
    >
    > Better yet, use 'our' instead of 'my':
    >
    > sub set_it {
    > our @array; # Lexical access to long-lived variable
    > @array = (1,2,3);
    > }
    > sub print_it {
    > our @array; # Access to same long-lived variable
    > }
    > set_it; print_it;


    I am a proponent of appropriate use of package variables but this in not
    appropriate.

    {
    my @array; # Block scoped variable
    sub set_it {
    @array = (1,2,3);
    }
    sub print_it {
    print "@array";
    }
    }

    set_it; print_it;
    Brian McCauley, Apr 3, 2005
    #12
  13. Joe Smith <> wrote:

    > Do not re-declare an already declared variable.



    Unless that is what you meant to do. <g>


    >> I liked this line from the coping with scope.
    >>
    >> When to Use my and When to Use local
    >> Always use my; never use local.

    >
    > I say "Always use my or our; never use local unless forced to."



    I prefer to talk about the type of variable to use rather than
    the details of how you get the type of variable that you want.

    So I like to say:

    Always prefer lexical over package variables, except when you can't.

    usually followed by some very brief examples of "when you can't":

    Perl's built-in variables

    Variables that must be visible across file boundaries

    Others too esoteric to mention in an introduction


    --
    Tad McClellan SGML consulting
    Perl programming
    Fort Worth, Texas
    Tad McClellan, Apr 3, 2005
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. D. Shane Fowlkes

    just tinkering with a Sub Routine in ASP.NET

    D. Shane Fowlkes, Nov 12, 2003, in forum: ASP .Net
    Replies:
    5
    Views:
    432
    Scott M.
    Nov 13, 2003
  2. Neo
    Replies:
    6
    Views:
    407
    Mark A. Odell
    Dec 2, 2003
  3. Ben
    Replies:
    2
    Views:
    878
  4. Lawrence D'Oliveiro

    Death To Sub-Sub-Sub-Directories!

    Lawrence D'Oliveiro, May 5, 2011, in forum: Java
    Replies:
    92
    Views:
    2,018
    Lawrence D'Oliveiro
    May 20, 2011
  5. C GIllespie

    Accessing an object in a sub-routine

    C GIllespie, Jun 10, 2004, in forum: Perl Misc
    Replies:
    2
    Views:
    86
    gnari
    Jun 10, 2004
Loading...

Share This Page