Exit a fork but return to parent

2019-08-11 08:11发布

I am having an issue with my first attempt at using fork.

The script seems to run fine until I need it to exit the fork and return to the main script.

Instead it exits the script entirely.

my @files = glob( "./input/<Input subnets>.txt" ) or die "Can't open HostInventory$!";     # Open the Host Inventory csv files for parsing

foreach my $file ( @files ) {

    open (CONFIG, '<', $file) or die "Can't <Input subnets>.txt$!";
    my @lines = <CONFIG>;
    chomp (@lines);

    $m = scalar @lines / 10;
    for ( $m ) {
        s/\..*//g
    };

    for ( my $i = 0; $i < @lines; $i += $m ) {

        # take a slice of elements from @files
        my @lines4 = @lines[$i .. $i + $m];

        if ( fork() == 0 ) {

            for my $n ( @lines4 ) {
                system("Nmap -dns-servers <IP of DNS server> -sn -v $n -oX ./input/ip360_DNS/ip360_DNS$n.xml --send-eth --reason");
            }

            exit;  
        }
    }

    wait for 0 .. @lines/$m;
}

At this point it should continue in the parent script and open a subroutine that parses the output of the scan. Instead it exits the script completely.

What am I doing wrong?

-=-=-=-=Update-=-=-=-= I tried the Parallel::ForkManager example below. When run as a standalone process it work perfectly. I am running the code inside of a subroutine though and when I try that, the Perl interpreter crashes. Suggestions?

#1/usr/bin/perl -w

use Parallel::ForkManager;
use strict;                                             # Best Practice
use warnings;                                           # Best Practice
use Getopt::Long;                                       # Add the ability to use command line options

 if (!@ARGV) {
    &help;
    exit 1
}

GetOptions(
    full =>                 \&full,
    temp =>                 \&temp,
);

                #######################################################################
                #######################################################################
                #                                                                     #
                #                      Call each function                             #
                #                                                                     #
                #######################################################################
                #######################################################################

sub temp {
    &speak;
    &simple;
    &speak2;
    exit;
}

sub full {
    &speak;
    &simple;
    &speak2;
    exit;
}   

sub speak {
    print "This is where I wait for 2 seconds\n";
    sleep (2);
}

my $process = $$;
print "$process\n";

sub simple {

    my $pm = new Parallel::ForkManager(10);
    $pm->run_on_finish(
    sub { $process;
        print "** PID $process\n";
        }
    );

    my @files = glob( "./ping.txt" ) or die "Can't open CMS HostInventory$!";     # Open the CMS Host Inventory csv files for parsing
    foreach my $file (@files){
        open (CONFIG, '<', $file) or die "Can't ip360_DNS File$!";
        my @lines = <CONFIG>;
        chomp (@lines);

        foreach my $n (@lines) {
            # Forks and returns the pid for the child:
            my $pid = $pm->start and next; 

            # ... do some work with $data in the child process ...
            system("ping $n >> ./input/$n.txt");

        }
        $pm->finish; # Terminates the child process
    }
}

sub speak2 {
    print "In new subroutine\n";
}

标签: perl fork
1条回答
成全新的幸福
2楼-- · 2019-08-11 08:35

First of all, your script doesn't "exit completely". It does wait for the children to finish. Or at least some of them. Your calculations are a little off.


You're skipping the last elements.

$m = scalar @lines / 10;
for ($m) {s/\..*//g};

is equivalent to

use POSIX qw( floor );

my $m = floor(@lines / 10);

but it should be

use POSIX qw( ceil );

my $m = ceil(@lines / 10);

You're performing the boundary elements twice.

my @lines4 = @lines[$i .. $i + $m];

should be

my @lines4 = @lines[$i .. $i + $m - 1];

wait for 0 .. @lines/$m;

should be

use POSIX qw( ceil );

wait for 1 .. ceil(@lines/$m);

or just

1 while wait > 0;

Easier to use Parallel::ForkManager.

use Parallel::ForkManager qw( );

my $pm = Parallel::ForkManager->new(10);  # Max number of children at a time.

$pm->run_on_finish(sub {
   my ($pid, $exit, $id, $signaled, $dumped, $data) = @_;
   my ($config_qfn, $target) = @$id;
   ...
});

for my $config_qfn (glob(...)) {
    open(my $config_fh, '<', $config_qfn)
       or die("Can't open \"$config_qfn\": $!\n");

    chomp( my @targets = <$config_fh> );

    for my $target (@targets) {
        my $pid = $pm->start([$config_qfn, $target])
           and next;

        exec(...)
           or die("exec: $!");
    }
}

$pm->wait_all_children();

By the way, you may have noticed I stopped doing things in batches. This allowed me to use exec instead of system, which reduces the number of forks by one for each batch, making it more efficient to not use batches.

查看更多
登录 后发表回答