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

Situation: I have a tool/command (tool.pl) that accepts max 5 hostnames as @ARGV. I have a file that contains hostnames, each host in a newline. There are 12 hosts in the file. How can I split the hostnames in the file to pass them to tool.pl with 5 hostnames as arguments

host1 host2 host3 host4 host5 host6 host7 host8 host9 host10 host11 host12

During the first iteration expected

 tool.pl host1 host2 host3 host4 host5

Second iteration

 tool.pl host6 host7 host8 host9 host10

Third iteration

 tool.pl host11 host12

Thanks for the help in advance

Replies are listed 'Best First'.
Re: split on every n lines
by choroba (Cardinal) on Apr 10, 2014 at 07:56 UTC
    If you are on a *nix box, you can profit from xargs:
    xargs -n5 tool.pl < hosts.txt
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: split on every n lines
by kcott (Archbishop) on Apr 10, 2014 at 06:14 UTC

    G'day sunil9009,

    You can do that like this:

    #!/usr/bin/env perl use strict; use warnings; use autodie qw{:all}; my $hosts = 2; my $tool = 'echo'; my @cmd = ($tool); while (<DATA>) { chomp; push @cmd, $_; if ($. % $hosts == 0) { system @cmd; @cmd = ($tool); } } system @cmd if @cmd > 1; __DATA__ host1 host2 host3 host4 host5

    Output:

    host1 host2 host3 host4 host5

    -- Ken

Re: split on every n lines
by AnomalousMonk (Archbishop) on Apr 10, 2014 at 05:58 UTC

    Pass the host file name to the Perl script on the command line as an argument. Change the script so that within it you open the host file (by name) and read n 'host' names at a time and process them. You might even make n an argument to the script along with the file name.

Re: split on every n lines
by monsoon (Pilgrim) on Apr 10, 2014 at 06:00 UTC
    undef $/; my @args = split /\n/, <DATA>; for(my $idx=4;$idx<@args+4;$idx+=5){ print join(" ", @args[$idx-4..$idx]), "\n"; } __DATA__ host1 host2 host3 host4 host5 host6 host7 host8 host9 host10 host11 host12
    There's probably a better way, but i can't think well at this late hour.
Re: split on every n lines
by hdb (Monsignor) on Apr 10, 2014 at 06:39 UTC

    Is there any advantage of not calling your tool simply 12 times with a single hostname each time?

Re: split on every n lines
by johngg (Canon) on Apr 10, 2014 at 10:24 UTC

    Another way would be to grab five lines at a time from your input. The &groupsOf subroutine runs the code block given as the first argument on however many items at a time, second argument, of the third and subsequent arguments which in the code below are the lines of the input file. Given this tool:-

    $ cat spw1081756tool.pl #!/usr/bin/perl # use strict; use warnings; use 5.014; say qq{$0 \@ARGV ->@ARGV<-}; $

    Running this code:-

    use strict; use warnings; use 5.014; sub groupsOf (&$@); open my $hostsFH, q{<}, \ <<EOD or die $!; host1 host2 host3 host4 host5 host6 host7 host8 host9 host10 host11 host12 EOD groupsOf { system q{spw1081756tool.pl}, map { chomp; $_ } @_; } 5, <$hostsFH>; close $hostsFH or die $!; sub groupsOf (&$@) { my $rcToRun = shift; my $groupsOf = shift; my $rcDoIt; $rcDoIt = sub { return $rcToRun->( map shift, 1 .. do { my $elems = scalar( @_ ); $groupsOf < $elems ? $groupsOf : $elems } ), @_ ? &$rcDoIt : (); }; return &$rcDoIt; }

    Gives this output:-

    ./spw1081756tool.pl @ARGV ->host1 host2 host3 host4 host5<- ./spw1081756tool.pl @ARGV ->host6 host7 host8 host9 host10<- ./spw1081756tool.pl @ARGV ->host11 host12<-

    I hope this is helpful.

    Cheers,

    JohnGG

Re: split on every n lines
by LanX (Saint) on Apr 10, 2014 at 11:33 UTC
Re: split on every n lines (tamwtdi)
by oiskuu (Hermit) on Apr 10, 2014 at 18:11 UTC

    Employing list utils:

    use List::MoreUtils 'part'; chomp(@$_), system("echo", @$_) for (part {$i++/5} <>);

Re: split on every n lines
by sunil9009 (Acolyte) on Apr 11, 2014 at 05:41 UTC

    awesome!! Thanks a ton hbm@ for so simple and easy solution. I underestimated the power of splice.

Re: split on every n lines
by sunil9009 (Acolyte) on Apr 10, 2014 at 19:52 UTC

    Can I have some simple solution. Something like this ? Its not working though. Dont know why

    #!/usr/bin/perl -w use strict; use warnings; open(my $fh, '<', '/tmp/list') or die "Unable to open file, $!"; my @entire_file=<$fh>; for my $i (0..$#entire_file) { my @group; push @group,$entire_file[$i] until ( $i % 5 == 0 ); `tool.pl @group`; }
      #!/usr/bin/perl use strict; use warnings; open my $fh, '<', 'list.txt' or die $!; chomp(my @hosts = <$fh>); close $fh; while (my @five = splice @hosts, 0, 5) { print qq{command @five\n}; } # prints: command host1 host2 host3 host4 host5 command host6 host7 host8 host9 host10 command host11 host12
      'until' starts an infinite loop when $i == 1