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

Hello Monks,

I am getting this error from a script that I have created. Initially I script with many subroutines inside, and I decide to split it on *.pm files so it can be easier readable/understandable.

Since I tried to modify it, although that I am at the final steps of my script I am getting this error:

Use of uninitialized value $selector in split at /usr/local/share/perl +/5.18.2/Net/OpenSSH/Parallel.pm line 141.

I opened the Net::OpenSSH::Parallel module at the specific line:

my @parts = split /\s*,\s*/, $selector;

My main.pl script is pasted underneath but I do not know if it can provide much of assistance:

#!/usr/bin/perl use FiLeS; use strict; use warnings; use Data::Dumper; use processLogFiles; use Fcntl qw(:flock); use feature qw(state); use Net::OpenSSH::Parallel; my %WARNS = (); my %dir_all = (); my %sudo_passwords = (); my $confFile = "conf.ini"; my $dirFile = "directories.ini"; my $objectFiles = FiLeS->new( "confRef" , "dirRef" ); my $refHashDir = $objectFiles->getFiles( $dirFile ); my $refHashconf = $objectFiles->getFiles( $confFile ); my $refHashDirectories = $objectFiles->makeDirectories( $refHashDir ); my $objectProcessLogFiles = processLogFiles->new( "refLogFile" , "refA +rrayConversion" , "refPrintOutput" ); # Find the version Ubuntu or Crux my @data_files = getOsDistribution( $refHashconf , $refHashDir ); my $refhashProcessTimestampFile = $objectProcessLogFiles->processData( + @data_files ); sub getOsDistribution { my ( $hashRefconf , $hashRefDir ) = @_; my @mps = sort keys ( $hashRefconf ); my $maximum_workers = @mps; my $maximum_connections = 2 * $maximum_workers; my $maximum_reconnections = 3; my %opts = ( workers => $maximum_workers, connections => $maximum_connections, reconnections => $maximum_reconnections ); my $pssh = Net::OpenSSH::Parallel->new(%opts); my $num = 0; my @stdout_fh = (); my @stderr_fh = (); my @log_files = (); foreach my $hash ( @mps ) { push (@log_files , "".$hashRefDir->{Directories}{log_dir}."/".$has +hRefconf->{$hash}{log}.""); open $stdout_fh[$num] , '>' , "".$hashRefDir->{Directories}{log_di +r}."/".$hashRefconf->{$hash}{log}."" or warn "unable to create file: $hashRefconf->{$hash}{log} - $ +!"; open $stderr_fh[$num], '>>', "".$hashRefDir->{Directories}{err_dir +}."/".$hashRefconf->{$hash}{error}."" or warn "unable to create file: $hashRefconf->{$hash}{error} - + $!"; $pssh->add_host( $hashRefconf->{$hash}{host} , user => $hashRefconf->{$hash}{user}, port => $hashRefconf->{$hash}{port}, password => $hashRefconf->{$hash}{psw}, default_stderr_fh => $stderr_fh[$num], default_stdout_fh => $stdout_fh[$num] ); $sudo_passwords{$hashRefconf->{$hash}{host}} = $hashRefconf->{$has +h}{psw}; $num++; } # hostname -I another way to get IP $pssh->push('*', command => 'cat /etc/issue; echo %HOST%' ); $pssh->run; closeFH( @stdout_fh , @stderr_fh ); my $refhashProcessData = $objectProcessLogFiles->processData( @log +_files ); my %version_hash = (); # Bind the IP's with the OS version foreach my $key ( keys $refhashProcessData ) { #print "$key: @{ $dev_info{$key} }\n"; $refhashProcessData->{$key}[0] = (split(/ /,$refhashProcessData->{ +$key}[0]))[0]; # Push the version into a hash pointing to the ip push( @{$version_hash{$refhashProcessData->{$key}[0]} } , $refhash +ProcessData->{$key}[1] ); } my $Crux_IPs = $version_hash{'CRUX'}; my $Ubuntu_IPs = $version_hash{'Ubuntu'}; my $refHashConvertArrayUbuntu = $objectProcessLogFiles->arrayConve +rsion( $Ubuntu_IPs ); my $refHashConvertArrayCrux = $objectProcessLogFiles->arrayConvers +ion( $Crux_IPs ); $pssh = Net::OpenSSH::Parallel->new(%opts); $num = 0; @stdout_fh = (); @stderr_fh = (); @log_files = (); foreach my $hash ( @mps ) { push (@log_files , "".$hashRefDir->{Directories}{log_dir}."/".$has +hRefconf->{$hash}{log}.""); open $stdout_fh[$num] , '>' , "".$hashRefDir->{Directories}{log_di +r}."/".$hashRefconf->{$hash}{log}."" or warn "unable to create file: $hashRefconf->{$hash}{log} - $ +!"; open $stderr_fh[$num], '>>', "".$hashRefDir->{Directories}{err_dir +}."/".$hashRefconf->{$hash}{error}."" or warn "unable to create file: $hashRefconf->{$hash}{error} - + $!"; $pssh->add_host( $hashRefconf->{$hash}{host} , user => $hashRefconf->{$hash}{user}, port => $hashRefconf->{$hash}{port}, password => $hashRefconf->{$hash}{psw}, default_stderr_fh => $stderr_fh[$num], default_stdout_fh => $stdout_fh[$num] ); $sudo_passwords{$hashRefconf->{$hash}{host}} = $hashRefconf->{$has +h}{psw}; $num++; } if ( grep { defined($_) } $refHashConvertArrayUbuntu ) { my @Ubuntu_cmds = ( 'echo %HOST%' , "service ntp stop" , "ntpd -gq" , "service ntp start" ); sub ubuntu { my ($label , $ssh , @cmd) = @_; foreach my $c (@cmd) { $ssh->system( {stdin_data => "$sudo_passwords{$label}\n"} , 'sudo' , '-Skp' , '' , '--' , split " " , $c ); } } foreach my $Ubuntu_ip ( @{$refHashConvertArrayUbuntu} ) { $pssh->push($Ubuntu_ip , parsub => \&ubuntu , @Ubuntu_cmds); } } # End of if grep $refHashConvertArrayUbuntu if ( grep { defined($_) } $refHashConvertArrayCrux ) { foreach my $Crux_ip ( @{$refHashConvertArrayCrux} ) { $pssh->push($Crux_ip , command => 'echo %HOST%; /etc/rc.d/ntpd + stop; ntpd -gq; /etc/rc.d/ntpd start;' ); } } $pssh->run; closeFH( @stdout_fh , @stderr_fh ); #/usr/local/dag/tools/dagclock -d dag0 none overin return @log_files; } sub closeFH { foreach my $file (@_) { close $file or warn $! ? "Error closing ".$file.": $!" : "Exit status $? from ".$file."\n"; } } local $SIG{__WARN__} = sub { my $message = shift; return if $WARNS{$message}++; logger('warning', $message); }; sub logger { my ( $level , $msg ) = @_; my $error = "$refHashDirectories->{Directories}{warn_dir}/error.er +r"; open my $out, '>>', "".$error."" or die "Could not open file: ".$error." - $!\n"; flock( $out , LOCK_SH ) or die "Could not lock '".$out."' - $!\n"; chomp $msg; my $datestring = localtime(); print $out "".$level." - ".$msg." - ".$datestring."\n"; close $out or die "Could not close file: ".$error." - $!\n"; }

In case you need me to post all my modules please feel free to ask me to.

Update: Adding all modules.

processLogFiles.pm

#!/usr/bin/perl use strict; use warnings; package processLogFiles; sub new { my $class = shift; my $devices = { refArrayProcess => shift, refArrayConversion => shift, refArrayPrintOutputFile => shift, }; bless $devices, $class; return $devices; } sub processData { use Fcntl qw( :flock ); my ( $devices , @stdin ) = @_; my %file_hash = (); foreach my $file (@stdin) { open my $file_handle , '<' , $file or warn "unable to open file: ".$file." $!"; flock( $file_handle , LOCK_SH ) or die "Could not lock '".$file."' - $!\n"; my $log_file = (split(/\//,$file))[-1]; # Remove \n character and also blank lines chomp(my @lines = grep /\S/, <$file_handle>); # Push the data into a hash push(@{$file_hash{$log_file}}, @lines); close $file_handle or warn "unable to close file: ".$file." $!"; } return $devices->{refArrayProcess} = \%file_hash if (%file_hash); } sub arrayConversion { use Fcntl qw( :flock ); my ( $devices , @twoDimensionArray ) = @_; my @result; while ( @twoDimensionArray ) { my $next = shift @twoDimensionArray; if ( ref($next) eq 'ARRAY' ) { unshift @twoDimensionArray , @$next; } else { push @result, $next; } } return $devices->{refArrayConversion} = \@result if (@result); } sub processTimestampFile { use Data::Dumper; my ( $devices , @log_file ) = @_; print Dumper \@log_file; exit 0; my %info = %{ shift() }; my $data = "data.txt"; open my $write , '>>' , $data or die "Could not open file: ".$data." - $!\n"; flock( $write , LOCK_SH ) or die "Could not lock '".$data."' - $!\n"; my %data_hash = (); foreach my $data_file ( sort { @{$info{$b}} <=> @{$info{$a}} } key +s %info ) { #print "$data_file: ", join(", ", sort @{ $info{$data_file} }), "\ +n"; $data_hash{$info{$data_file}[0]} = $info{$data_file}[3]; printf $write "%s %s\n" , $info{$data_file}[0] , $info{$data_file} +[3]; } close $write or die "Could not close '".$data."' - $!\n"; #return $devices->{refArrayPrintOutputFile} = \%data_hash if (%dat +a_hash); } 1;

FiLeS.pm

#!/usr/bin/perl use strict; use warnings; package FiLeS; sub new { my $class = shift; my $files = { dirRefFile => shift, confRefFile => shift, }; bless $files, $class; return $files; } sub getFiles { use Config::IniFiles; use Fcntl qw( :flock ); my ( $files , $dataFiles ) = @_; open my $fh , '<' , "".$dataFiles."" or die "Could not open file: ".$dataFiles." - $!\n"; flock( $fh , LOCK_SH ) or die "Could not lock '".$dataFiles."' - $!\n"; tie my %ini, 'Config::IniFiles', ( -file => "".$dataFiles."" ) or die "Error: IniFiles->new: @Config::IniFiles::errors"; close $fh or die "Could not close '".$dataFiles."' - $!\n"; return $files->{dirRefFile} = \%ini if (%ini); } sub makeDirectories { my ( $files , $hash_dir ) = @_; foreach my $dir ( sort keys %{ $hash_dir } ) { #print $dir . " {\n"; foreach my $keys ( keys %{ $hash_dir->{ $dir } } ) { #print "\t" . $keys . " \t=> "; foreach my $path ( $hash_dir->{ $dir }->{ $keys } ) { #print $path . "\n"; unless(-e $path or mkdir $path) { mkdir ($path , 0755); } } } #print "}\n"; } return $files->{ dirRefFile } = $hash_dir if ( $hash_dir ); } 1;

The conf.ini file:

[MP 100] host = 0.0.0.0 user = username psw = password port = 22 log = MP_100.log error = MP_100.err [MP 101] host = 0.0.0.0 user = username psw = password port = 22 log = MP_101.log error = MP_101.err

The directories.ini file:

[Directories] log_dir = /home/LOG err_dir = /home/ERROR warn_dir = /home/WARN

Thanks in advance everyone for their time and effort to assist me.

Seeking for Perl wisdom...on the process of learning...not there...yet!
  • Comment on Use of uninitialized value $selector in split at /usr/local/share/perl/5.18.2/Net/OpenSSH/Parallel.pm line 141.
  • Select or Download Code

Replies are listed 'Best First'.
Re: Use of uninitialized value $selector in split at /usr/local/share/perl/5.18.2/Net/OpenSSH/Parallel.pm line 141.
by NetWallah (Canon) on Jan 29, 2015 at 04:02 UTC
    The $selector is the first argument passed to:
    $pssh->push($SELECTOR,....);
    It looks like that value is undef, possibly somewhere in your code like at :
    $pssh->push($Ubuntu_ip , parsub => \&ubuntu , @Ubuntu_cmds);
    Are you sure that $Ubuntu_ip has a value ?

    Perhaps you could add debugging statements, or run under the perl debugger.

            "You're only given one little spark of madness. You mustn't lose it."         - Robin Williams

      Hello NetWallah,

      Thank you for your time and effort, reading and replying to my question. Well unfortunately the code works just fine, so I do not know where this warning comes from. I have added all the modules that I am using just in case that someone want to experiment.

      Seeking for Perl wisdom...on the process of learning...not there...yet!
Re: Use of uninitialized value $selector in split at /usr/local/share/perl/5.18.2/Net/OpenSSH/Parallel.pm line 141.
by GotToBTru (Prior) on Jan 29, 2015 at 04:15 UTC

    The error message tells you what the problem is. $selector has not been initialized. Open the package and find out where any value is assigned to this variable. Most likely, some place where you think you assign a value, you don't. Trace it back from there. It would make sense to focus on the package subroutines you call in your code.

    Dum Spiro Spero

      Hello GotToBTru,

      Thank you for your time and effort reading and replying to my question. Well to be honest I am not really familiar with debugging Perl. I searched online and I found that I should execute the code like perl -d main.pl. When I do that the script stops at line 10 and gives me the following error when I type l:

      Loading DB routines from perl5db.pl version 1.39_10 Editor support available. Enter h or 'h h' for help, or 'man perldebug' for more help. main::(main.pl:10): our %WARNS = (); DB<1> l 10==> our %WARNS = (); 11: my %dir_all = (); 12: my %sudo_passwords = (); 13 14: my $confFile = "conf.ini"; 15: my $dirFile = "directories.ini"; 16 17: my $objectFiles = FiLeS->new( "confRef" , "dirRef" ); 18: my $refHashDir = $objectFiles->getFiles( $dirFile ); 19: my $refHashconf = $objectFiles->getFiles( $confFile ); DB<1>

      How can I proceed from that point. I tried all commands in debug help.

      I have added all missing modules just in case that someone wants to experiment.

      Seeking for Perl wisdom...on the process of learning...not there...yet!

        My suggestion is actually to do some homework before you start the debugger, because it will help you figure out what you can skip over and what you need to actually watch closely. Look in Parallel.pm at line 141, and figure out how the value of $selector is assigned. See what subroutine within Parallel.pm you're in, and look in your code for where you call that particular subroutine. That's where you need to start.

        Your next step is to go to here to read the Perl debugger tutorial. Are you familiar with debuggers? It allows you to execute your program one statement at a time, and inspect the values of variables. It is an invaluable aid to finding and fixing bugs. Your research will tell you where to set a breakpoint in your code; the debugger will execute the lines up to the breakpoint and stop there. Now you can inspect your variables and make sure that the value which will end up in $selector has the value you expect.

        Update: looks like NetWallah has already done some of this for you. Either put a watch on $Ubuntu_ip, or set a breakpoint for line 144, the foreach my $Ubuntu_ip .... Inspect $refHashConvertArrayUbuntu to see if it has the values you expect.

        Dum Spiro Spero