Re: Problem with exit status of bash script
by Athanasius (Archbishop) on Dec 04, 2014 at 04:41 UTC
|
Hello dizzyd719, and welcome to the Monastery!
If your code:
system("ping ... &");
$result = $?;
worked as you expect, what advantage would there be in backgrounding the ping process? Whether running in the foreground or the background, it would still have to complete before the system call returned.
But with ping backgrounded you report a significant speedup. I suspect what is happening is this: the call to system("ping ... &") spawns a shell subprocess (1) which in turn spawns the call to ping as a background process (2). Process (1) then immediately returns to the system call a status code indicating whether process (2) was spawned successfully. So of course you aren’t getting the correct exit statuses, since the return values from (2) never make it back to your Perl script.
The speedup you are seeing suggests that you will indeed benefit from running the ping commands in parallel (asynchronously). So you need another way to do this and get their exit statuses. Have a look at fork or a module such as Parallel::ForkManager. (And see perlfaq8#How-do-I-start-a-process-in-the-background%3f.)
Hope that helps,
| [reply] [d/l] [select] |
|
|
Thanks, yeah after spitting out the errors codes (always 0) I realized that I wasn't getting the correct codes. I started looking into the "fork" option and just figuring out how to communicate between processes.
do you have any good docs for me to read about IPC in perl? my research so far is leading me into "ALERTING A PROCESS VIA A SIGNAL"
| [reply] |
|
|
do you have any good docs for me to read about IPC in perl?
Sure:
Hope that helps,
1Tom Christiansen, brian d foy & Larry Wall, with Jon Orwant, Programming Perl, 4th Edition, 2012.
| [reply] |
Re: Problem with exit status of bash script
by Anonymous Monk on Dec 04, 2014 at 06:12 UTC
|
Athanasius is correct, & is a shell thing and doesn't do what you want (man bash: "If a command is terminated by the control operator &, the shell executes the command in the background in a subshell. The shell does not wait for the command to finish, and the return status is 0."). And you don't want the shell in the first place. Use a module, or just use fork, exec and wait... this is what bash does anyway, except it doesn't wait in your script, so you don't get ping's exit code.
Something like that:
use strict;
use warnings;
use autodie;
use POSIX ':sys_wait_h';
my @sites = qw(
www.perlmonks.org
www.stackoverflow.com
www.whitehouse.gov
);
open my $stdout, '>&', \*STDOUT; # dup STDOUT
open STDOUT, '>', '/dev/null'; # to make ping shut up
my %kids;
for my $site (@sites) {
my $pid = fork;
$pid == 0 and exec 'ping', '-c', '3', $site;
$kids{$pid} = $site;
}
while ( ( my $kid = wait ) != -1 ) {
print $stdout "$kids{$kid} returned $?\n";
}
Output:
www.stackoverflow.com returned 0
www.perlmonks.org returned 0
www.whitehouse.gov returned 0
| [reply] [d/l] [select] |
|
|
interesting code you have there. I need some helping understanding it though
after you fork, does the child process actually modify "my %kids" ? I tried to do something similar with an array, but when I called it I got back a reference to an array. do you know why? (code is below)
in your second loop, you wait for the kids to finish their process and print to stdout the actual return value, is this possible to track? for example I want to have this run all day so I'm thinking I could keep a hash that has these return values and times for tracking purposes
foreach $element (@updevices){
@ip = split(':',$element);
die "Could not fork()\n" unless defined ($pid = fork);
if ($pid) { push @pids, $pid; next;}
system("ping $ip[2] 1 > /dev/null");
$result = $?;
print "ping $ip[0] $ip[2] $result\n";
if ( $result != 0)
{
print "$ip[0] is dead\n";
push(@dead, $ip[0]);
}
exit;
}
| [reply] [d/l] |
|
|
after you fork, does the child process actually modify "my %kids" ?
No it doesn't because "The 'exec' function executes a system command and never returns". So
...
my $pid = fork;
$pid == 0 and exec 'ping', '-c', '3', $site;
# child ($pid 0) never reaches code below.
# exec doesn't return, it can only exit
# or it can fail to find ping, but I use autodie
# (for this kind of program that's probably
# not a great idea in something
# that can be called 'production'... but w/e)
$kids{$pid} = $site; # only parent gets here
...
I tried to do something similar with an array, but when I called it I got back a reference to an array. do you know why? (code is below)
What did you expect? Also I don't see any reference to an array (reference in Perl is something different). Anyway, parent can use the array @pids because why not.
foreach $element (@updevices){
@ip = split(':',$element);
die "Could not fork()\n" unless defined ($pid = fork);
if ($pid) { push @pids, $pid; next;}
# ^ this is parent code, it pushes $pid to array
# and goes back to the top of the loop
# below is child code
# it does something and then exits
system("ping $ip[2] 1 > /dev/null");
$result = $?;
print "ping $ip[0] $ip[2] $result\n";
if ( $result != 0)
{
print "$ip[0] is dead\n";
push(@dead, $ip[0]);
}
exit;
# ^ child exits here
# and basically stops (that's how exit works, after all)
# and its exit code is 0; see perdoc -f exit
}
# after parent is done with the loop
# it continues here
# it has the array @pids
# and all other global vars that your script
# is full of...
BTW, note that $? is not exactly exit code. See the manual for details.
in your second loop, you wait for the kids to finish their process and print to stdout the actual return value, is this possible to track? for example I want to have this run all day so I'm thinking I could keep a hash that has these return values and times for tracking purposes
There are probably tons of modules on CPAN that help to automatize these kinds of things... I'd really recommend to look there.
If not, then you probably should use signal handlers ($SIG{CHLD} specifically). See peripc. | [reply] [d/l] [select] |
|
|
|
|
Re: Problem with exit status of bash script
by NetWallah (Canon) on Dec 04, 2014 at 06:14 UTC
|
Here is some old code that does parallel ping using perl Threads.
"You're only given one little spark of madness. You mustn't lose it." - Robin Williams
| [reply] [d/l] |
Re: Problem with exit status of bash script
by karlgoethebier (Abbot) on Dec 04, 2014 at 10:29 UTC
|
fping -C 1 perlmonks.org cpan.org stackoverflow.com
stackoverflow.com : [0], 84 bytes, 89.3 ms (89.3 avg, 0% loss)
perlmonks.org : [0], 84 bytes, 163 ms (163 avg, 0% loss)
cpan.org : [0], 84 bytes, 155 ms (155 avg, 0% loss)
perlmonks.org : 163.50
cpan.org : 155.29
stackoverflow.com : 89.33
fping -C 1 -q perlmonks.org cpan.org stackoverflow.com
perlmonks.org : 162.75
cpan.org : 155.49
stackoverflow.com : 88.75
Edit: Fixed funny typo: perlmonks.
Regards, Karl
«The Crux of the Biscuit is the Apostrophe»
| [reply] [d/l] |