Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation

by greenFox (Vicar)
on Jul 25, 2002 at 12:26 UTC ( #185177=sourcecode: print w/replies, xml ) Need Help??
Category: Utility Scripts
Author/Contact Info Murray Barton <muzza at iinet dot net dot au>
Description: -a utility for running the same command across a group of hosts.
#!/usr/bin/perl -w
# run a command on multiple hosts!
# reads hosts from ~/rhosts
# if ~/rhosts is
#   host  group1,group3
#   host2  group2,group3
#   host3  group2
# then 
# -g group2 ls
# will run ls on host2 and host3
# great for run this command on "print hosts" or "solaris 8" machines 
# red hat machines etc.
# Requires ssh installed- yeah I could have used Net:SSH, 
# not sure if that would any value though :)
# started out as a quick and dirty one off 
# shell script and has grown...

use strict;
use Sys::Hostname;
use Getopt::Std;
my $home=get_home();
my %settings = (
          domain       => '',
          DEBUG        => 0,
          SSH          => "/usr/local/bin/ssh",
          SCP          => "/usr/local/bin/scp",
          HOST_FILE    => "$home/rhosts",
          runlocally   => 0,


sub main_loop {

  my %args;
  getopts("g:hlnz", \%args);  # see print_help() for a description of 
  print_help() and exit if $args{h};
  print_help() and exit if ! $args{g};
  my $host_group = $args{g} || '';
  my $no_prompt  = 1 if $args{n};
  my $no_errors  = 1 if $args{z};
  $settings{runlocally} = 1 if $args{l};
  print_help() and die "Specify command to run!\n" if ( ! scalar @ARGV

  # the shell expands ~ and $home might be someplace different
  # on the destination host...
  my @command = map { s/^$home/~/; $_ } @ARGV;
  unshift @command, $settings{SSH};
  push @command, " 2>/dev/null" if $no_errors; 

  my @dest_hosts=get_hosts($settings{HOST_FILE}, $host_group);
  for my $host (@dest_hosts){
    unless ( $no_prompt ){
      print "Run @ARGV on $host [y/n]: ";
      chomp (my $answer = <STDIN>);
      next if ( $answer !~ /^y/i );
    my @cmd = @command;
    splice(@cmd, 1, 0, $host);  # insert the hostname
    if ( $settings{runlocally} and $host eq $settings{localhost}){
      shift @cmd; shift @cmd;  # remove ssh and $hostname
    print "Running [@cmd]\n" if $settings{DEBUG};
    my @result = `@cmd`;
    print "$host: ", @result, "\n";

sub get_hosts {
  my $hosts_file = shift || die "sub get_hosts did not get a required 
  my $host_group = shift || die "sub get_hosts did not get a required 
  my $localhost = hostname();
  $localhost = (gethostbyname("$localhost.$settings{domain}"))[0] || $
  print "localhost: [$localhost]\n" if $settings{DEBUG};
  $settings{localhost} = $localhost;
  my @hosts;
  open (HOSTS, $hosts_file) || die "Could not open $hosts_file : $!\n"
  while (<HOSTS>){
    next if /^\s*$/;
    next if /^\s*#/;
    my ($host, $groups) = split /\s+/;
    $host .= ".$settings{domain}" if ($host !~ /\./);
    my %groups = map { $_, 1 } split /,/, $groups;
    next if ( $host eq $localhost and ! $settings{runlocally});
    next if ( ! $groups{$host_group} and $host_group ne "all");
    print "Selecting [$host]\n" if $settings{DEBUG};
    push @hosts, $host;
  return @hosts;

sub get_home {
  my @pwd = getpwuid($<);
  my $home = $ENV{HOME} || $ENV{LOGDIR} || $pwd[7]
    or die "Could not determine home directory for $<";
  return $home;

sub print_help {
  print  " -g <group> [options] file\n\n",
      "\twhere <group> is a group in your ~/rhosts file or \"all\"\n",
      "\t-h print this message\n",
      "\t-l run on local host\n",
      "\t-n no prompt just do it!\n",
      "\t-z suppres error messages\n";
Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: sourcecode [id://185177]
[shmem]: ;-)
[choroba]: also, you get stronger by carrying the rune stones along
[erix]: haha
[karlgoethebier]: shmem: This repertoire is a real challenge.
Discipulus mwhwhaa..
[Discipulus]: sucked in traslation.. was'nt a movie?
[karlgoethebier]: adds "Der abenteuerliche Simplicissimus" by Hans Jakob Christoffel von Grimmelshausen
Corion joins another telephone call :-/

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (14)
As of 2017-05-24 08:00 GMT
Find Nodes?
    Voting Booth?