MrAZ
MrAZ

Reputation: 444

Pass hash to subroutine comes to error in perl

My code as below,

my %srvs = (
    serv_1 => {
         agents => 'agent_path',
         ...
         ...
    },
    serv_2 => {
         <same like above>
    },
    serv_3 => {
          ...
    ........
    ........
    serv_8 => {
            ...
    },
);

        switch ("$option") {
                case 1  { print "Option 1 selected. \n"; &main; }
                case 2  { print "Option 2 selected. \n"; stop(\%srvs); }
                case 3  { print "Option 3 selected. \n"; start(\%srvs); }
                else    { print "Option are not valid. \n"; exit 0; }
        }

sub stop {
        my $servs = @_;

        foreach my $s_name (sort keys %{$servs}) {
                print "$s_name \n";             

                my $ssh = Net::OpenSSH->new("<user_id>\@$s_name", timeout=>30);
                $ssh->error and die "Unable to connect $s_name  --->  " . $ssh->error and print "\n";

                $ssh->pipe_in("perl /<path>/<script_name>.pl stop all") or die "Unable to run command.\n";
        }

}

What I try to do is get a server name which is the keys of %srvs, which is (serv_1, serv2, etc.)

When I run the code, I received below error,

Can't use string ("1") as a HASH ref while "strict refs" in use at .pl line 260, <> line 1.

I also try different method which is call as array from the case control statement,

----
----
case 2  { print "Option 2 selected. \n"; my @s = sort keys %srvs; stop("@s"); }
---
---
sub stop {

        my @servs = @_;

        foreach my $s_name (@serv) {
                print "$s_name \n";             

                my $ssh = Net::OpenSSH->new("<id_server>\@$s_name", timeout=>30);
                $ssh->error and die "Unable to connect $s_name  --->  " . $ssh->error and print "\n";

                $ssh->pipe_in("<path_name> <script_name>.pl stop all") or die "Unable to run command.\n";
        }
}

This code can be process, however it list all the server name (which is all the keys of %srvs) in single flat line, I cannot divide the list using foreach.

Need assist since quite confuse with the passing method.

Upvotes: 1

Views: 194

Answers (1)

zdim
zdim

Reputation: 66883

The assignment is in the scalar context in your sub stop on the line

my $servs = @_;

so $servs receives the number of elements of @_, that is 1 in your code. Then the attempt to dereference that 1 with %{$servs} draws the error.

Change it to my ($servs) = @_; where the () results in the list context for =

A few comments.

  • The hash with servers is likely to be used mostly via its reference. Then why not use a hashref, my $serv = { ... }

  • There is never a reason to quote a scalar, like "$option"; just switch($option)

  • The & in front of a sub is quite special; you mostly likely need main() instead of &main

  • Second code sample has stop("@s");, whereby @s is interpolated inside "". So the sub receives a single string: array elements with spaces between them. You need stop(@s)

You seem to be using Switch module. It is a rather non-trivial source filter; surely there are other ways to do what you need. The feature switch is experimental, too. See Switch Statements in perlsyn


  The my @args = @_; serves the same purpose of course. Then process @args suitably.

A commonly seen way to retrieve the first argument is also

sub fun {
    my $first_arg = shift;  # same as: shift @_;
    ...
}

The shift removes an element from the front of its argument (array), and returns it; by default it acts on @_ which you thus don't have to write.

This is often seen in object-oriented code, to get the object off of @_ so that @_ can then be worked with more easily. But it is also often used when @_ has a single argument, for convenience.

Upvotes: 2

Related Questions