#!/usr/bin/perl -w # # rcmd.pl # # run a command on multiple hosts! # reads hosts from ~/rhosts # # if ~/rhosts is # host group1,group3 # host2 group2,group3 # host3 group2 # then # rcmd.pl -g group2 ls # will run ls on host2 and host3 # # great for run this command on "print hosts" or "solaris 8" machines or # red hat machines etc. # # Requires ssh installed- yeah I could have used Net:SSH, # not sure if that would any value though :) # # rcmd.pl 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 => 'some.net.au', DEBUG => 0, SSH => "/usr/local/bin/ssh", SCP => "/usr/local/bin/scp", HOST_FILE => "$home/rhosts", runlocally => 0, ); main_loop(); exit; sub main_loop { my %args; getopts("g:hlnz", \%args); # see print_help() for a description of options 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 = ); 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 argument\n"; my $host_group = shift || die "sub get_hosts did not get a required argument\n"; my $localhost = hostname(); $localhost = (gethostbyname("$localhost.$settings{domain}"))[0] || $localhost; print "localhost: [$localhost]\n" if $settings{DEBUG}; $settings{localhost} = $localhost; my @hosts; open (HOSTS, $hosts_file) || die "Could not open $hosts_file : $!\n"; while (){ next if /^\s*$/; next if /^\s*#/; chomp; 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; } close(HOSTS); 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 "rput.pl -g [options] file\n\n", "\twhere 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"; }