退出分叉但返回父级

时间:2017-07-13 16:52:58

标签: perl fork

我第一次尝试使用fork时出现问题。

脚本似乎运行正常,直到我需要它退出fork并返回主脚本。

相反,它完全退出脚本。

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;
}

此时它应该在父脚本中继续并打开一个子程序来解析扫描输出。相反,它完全退出脚本。

我做错了什么?

- = - = - = - =更新 - = - = - = - = 我尝试了下面的Parallel :: ForkManager示例。当作为独立进程运行时,它可以完美地运行。我在子程序中运行代码但是当我尝试时,Perl解释器崩溃了。建议?

#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";
}

1 个答案:

答案 0 :(得分:5)

首先,您的脚本不会“完全退出”。它确实等待孩子们完成。或者至少其中一些。你的计算有点偏。

你正在跳过最后的元素。

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

相当于

use POSIX qw( floor );

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

但它应该是

use POSIX qw( ceil );

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

您正在执行两次边界元素。

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

应该是

my @lines4 = @lines[$i .. $i + $m - 1];
wait for 0 .. @lines/$m;

应该是

use POSIX qw( ceil );

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

或只是

1 while wait > 0;

更易于使用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();

顺便说一下,你可能已经注意到我已经停止批量做事了。这使我可以使用exec代替system,这样可以减少每批次的分叉数量,从而提高批量使用效率。