Net::Ping Times Out - perl

I have a very simple script to ping a host and find out the duration of the ping
use 5.010;
use Net::Ping;
my $p = Net::Ping->new();
my ($ret, $duration, $ip) = $p->ping('google.com');
say $ret;
say $duration;
say $ip;
For some reason this keeps timing out ($ret returns 0 and $duration returns 5 seconds)
What is the reason for this?

Related

Strange output in printing a grep -c return

Below is a shell program, it's just me testing how to tell if the same Perl script is already running using the same parameters.
It works, but what strikes me as odd is the trailing zero after the count of lines. I don't see where in my code that zero would be printed. If I run that grep command from the command line it just returns the count, no trailing '0', but it doesn't work that way in the code.
Any clues anyone?
Thanks
The App
#!/usr/bin/perl
use CGI;
$|=1;
my $q = CGI->new();
my $userid = $q->param("u");
my $check = "'perly.pl u=" . $userid . "'";
my $return= system("ps aux | grep $check | grep -v 'grep' -c");
print $return;
print "\n";
while(1)
{
print "$userid...";
sleep(3);
}
exit 0;
The output
2 0
PlasticProgrammer..PlasticProgrammer..PlasticProgrammer..PlasticProgrammer..PlasticProgrammer..PlasticProgrammer..PlasticProgrammer..PlasticProgrammer..PlasticProgrammer..PlasticProgrammer..PlasticProgrammer..
You can easily capture the output and exit value of a command using Capture::Tiny. Also, when using the built-in system, always make sure to check that the execution succeeded, if it failed this is indicated by a return value of -1.
use strict;
use warnings;
use Capture::Tiny 'capture_stdout';
my $check = "perly.pl u=foo";
my ($stdout, $exit) = capture_stdout { system 'pgrep', '-fc', $check };
die "pgrep failed: $!" if $exit == -1;
Remember that your output will most likely end in a newline, even just a count, so you probably want to chomp it.
You can also use the backticks/qx operator to return just the STDOUT, but this will always pass the command through the shell, requiring you to use String::ShellQuote on your argument containing user input as noted by #ikegami.
use strict;
use warnings;
use String::ShellQuote;
my $check = shell_quote "perly.pl u=foo";
my $stdout = `pgrep -fc $check`;
die "pgrep failed: $!" if $? == -1;
An alternative is IPC::System::Simple, which provides capturex, a form of the backticks operator that takes a list of arguments like system and never passes them through the shell. By default it will throw an exception if the command fails or if there's a nonzero exit code, but you can specify to allow certain exit codes. Since pgrep returns a nonzero exit code if there's no matches, you want to allow nonzero exit codes.
use strict;
use warnings;
use IPC::System::Simple qw(capturex EXIT_ANY $EXITVAL);
my $check = "perly.pl u=foo";
my $stdout = capturex EXIT_ANY, 'pgrep', '-fc', $check;
my $exit = $EXITVAL;
In case anyone is looking for a solution to this, good ideas up top but in the end I chose to create a unique temp file and pipe the output to that file.
Many ways, I found this the one that felt right for me.
#!/usr/bin/perl
use CGI;
use File::Temp;
$|=1;
my $q = CGI->new();
my $userid = $q->param("u");
my $check = "'perly.pl u=" . $userid . "'";
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$year += 1900;
$mon++;
my $uFile = $userid . $year . $mon . $mday . $hour . $min . $sec . ".dat";
my $command = "ps aux | grep $check | grep -v 'grep' -c > $uFile";
system($command);
if (open(my $fh, "$uFile"))
{
while (my $line = <$fh>)
{
if($line>1)
{
print"\nApp is already running";
}
}
close($fh);
unlink($uFile);
}
exit 0;

Perl custom run time format

I have an issue and this is rather my last resort before I give up, Im rather a noob with Perl and I've about reached the end of the internet searching for a solution.
***I do not have permission to install anything so it must be native to Perl5
I have a script and I need to calculate the total runtime of the script, and output the result in 00.00 "minutes.seconds" stored in a variable.
Here's a failed attempt:
#!/usr/bin/perl
use Time::Piece;
use POSIX qw(strftime);
my $start = localtime->strftime($unixtime);
sleep(10);
my $end = localtime->strftime($unixtime);
my $diff = $end - $start;
my $runtime = printf("%M.%S", $diff);
print $runtime;
I definitely have played with this a bit and was able to get "10" seconds as a result, however that is not the proper format. If the script ran for say 10 seconds, the output should be "00.10".
If the script ran for say 1 minute and 55 seconds the output should be "01.55".
Is there any way this can be done?
I searched on this and found 1 article however not even close... REF: perl different time format output
No need for Time::Piece!
my $start = time;
sleep(10);
my $end = time;
my $diff = $end - $start;
my $runtime = sprintf '%d:%02d', int($diff / 60), $diff % 60;
print "$runtime\n";
This should do the trick:
#!/usr/bin/perl
use Time::Piece;
my $start = localtime;
sleep(10);
my $end = localtime;
my $diff = $end - $start;
my $minutes = int $diff->minutes;
my $seconds = $diff->seconds % 60;
my $output = sprintf '%02d.%02d', $minutes, $seconds;
print "$output\n";

LWP::Simple and cron

This script works every time from command line but very rarely from cron job. I can run it like this: ./chort.pl
But it dies very frequently (not always) with "wrong values" message while calling it from cron:
*/2 10-18 * * 1-5 /path/to/chort.pl >> /tmp/chort.pl 2>&1
When it dies, than the $res is empty. print "*$res*\n"; prints **. So , it seems, that there is a problem with getting of webpage while calling from cron.
Here a snippet:
sub getLSEVal
{
my $fourWayKey = shift;
my $url = "http://pat.to.url";
my $res;
timeout 280 => sub {
$res = get $url ;
return (-2, -2, -2 );
};
print $res;
$res =~ /Price\| High \| Low .*?<tr class="odd">.*?<td>(.*?)<\/td>.*?<td>(.*?)<\/td>.*?<td>(.*?)<\/td>/msig;
my $c = $1;
my $h = $2;
my $l = $3;
print "$1 $2 $3\n";
die ("wrong values") if $c !~ /\d+\.?\d*/ or $h !~ /\d+\.?\d*/ or $l !~ /\d+\.?\d*/;
return ($c, $h, $l);
}
You probably need to use LWP::UserAgent, which allows you a higher level of control. LWP::Simple sometimes is too abstract to know what is happening when a problem appears.

Unable to inspect variable

I'm having a very difficult time inspecting the $return variable. The print "return = ". $return ."\n"; always comes back blank even though the process is still running. I do receive a warning about uninitialized variable. Can someone please explain?
my $process="MInstaller";
my $return=` ps -eaf |grep $process | grep -v grep`;
sub chk_proc{
print "in chk_proc\n";
print "\n";
print "return = ". $return ."\n";
while ( my $return ne "" ) {
sleep(5);
};
};
You're close. Your code doesn't works, because the variable $return in the
while ( my $return ne "" ) {
is another variable (declared in the scope of while) as your first $return.
You can try the next:
use 5.014;
use warnings;
chk_proc('[M]Installer'); #use the [] trick to avoid the 'grep -v grep :)
sub chk_proc{ while( qx(ps -eaf |grep $_[0]) ) {sleep 5} };
Are you using use warnings; and use strict;?
What about using pgrep instead of ps?
What happens if $return returns more than one line?
Your program would flow better if your subroutine merely checked to see if the process is running and you used that in another loop.
Here, my check process subroutine returns a list of all the processes it find. I can use this in my loop to see if the process itself has stopped. I could have used qx() to get a process list, then use split to create a list of processes.
use warnings;
use strict;
use feature qw(say);
use constant {
PROCESS => "MInstaller",
SLEEP => 5,
};
while ( process_check( PROCESS ) ) {
say qq(Process ) . PROCESS . qq( is running...);
sleep SLEEP;;
}
say qq(Process ) . PROCESS . qq( has ended.);
sub process_check {
my $process = shift;
open ( my $process_fh, "-|", "pgrep $process" );
my #process_list;
while ( my $line = <$process_fh> ) {
chomp $line;
push #process_list, $line;
}
close $process_fh;
return #process_list;
}

print result from all devices on array

I just write this script however the script only print one result not the results from all devices. I belive my error is on print section but I couldn't figure out.
Note :- the host file has 30 devices list but the script print the result of the last device only.
#!/usr/bin/perl
$host_file = "/usr/local/bin/test/host2";
open (PACKETLOSS,"$host_file") or die "Cannot Open Extracted host file";
# Put Extracted data into an array
#extracted_array=<PACKETLOSS>;
chomp(#extracted_array);
foreach(#extracted_array) {
#words = split;
$host = $words[0];
}
$extracted_array[$ping_idx] = `/usr/sbin/ping -s -t 10 $host 56 2 2>&1`;
$ping_idx++;
($packet_loss) = ($ping =~ m/packets received, (\d+)% packet loss/);
($round_trip) = ($ping =~ m/round-trip.*\(ms\).*min\/avg\/max\/stddev = \d+\.\d+\/(\d+\.\d+)\/.*/);
print " $host $round_trip ms Average Latency and $packet_loss Packet loss\n";
Make your foreach loop close at the very bottom of the code.
foreach(#extracted_array) {
#words = split;
$host = $words[0];
$extracted_array[$ping_idx] = `/usr/sbin/ping -s -t 10 $host 56 2 2>&1`;
$ping_idx++;
($packet_loss) = ($ping =~ m/packets received, (\d+)% packet loss/);
($round_trip) = ($ping =~ m/round-trip.*\(ms\).*min\/avg\/max\/stddev = \d+\.\d+\/(\d+\.\d+)\/.*/);
print " $host $round_trip ms Average Latency and $packet_loss Packet loss\n";
}
Cause you are closing foreach and then performing the operation. IT should be
foreach(#extracted_array)
{
#words = split;
$host = $words[0];
$extracted_array[$ping_idx] = `/usr/sbin/ping -s -t 10 $host 56 2 2>&1`;
$ping_idx++;
($packet_loss) = ($ping =~ m/packets received, (\d+)% packet loss/);
($round_trip) = ($ping =~ m/round-trip.*\(ms\).*min\/avg\/max\/stddev = \d+\.\d+\/(\d+\.\d+)\/.*/);
print " $host $round_trip ms Average Latency and $packet_loss Packet loss\n";
}