#!/bin/sh # # $Id$ # sshall: ssh to multiple hosts, *last* arg is command # with -i, also accepts input ... I'd rather dup stdin or so, but how? PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/usr/etc; export PATH tmpfile=/tmp/sshall-$$ # error handling trap 'rm -f $tmpfile; exit' 1 2 3 4 13 15 #--- cmdline parsing ---# # Puke() { if [ -n "$*" ]; then echo Fatal error: $* 1>&2; fi cat <&2 Usage: $0 [-v] [-i] [-e] [-b] [-u user] [-H] [-Y] [-P] host1 [host2 [...]] "command" to issue "ssh host command" for every host use -i flag to supply input, -e to redirect stderr to stdout, -v for progress messages, -b to start in the background, -u user to connect as the given user, -H to check the hostnames with 'host', -Y to check them with 'ypmatch', -P to check them with 'ping', -o text to pass the given option through to ssh note: the effect of -i is to call ssh without the -n flag take care: -b may fill up your process table if used on many hosts ZZ exit 1 } input= hostlist= verbose= bg= check_w_host= check_w_ypmatch= check_w_ping= user_prefix= while : do case "$1" in -h|-help|\?*) Puke;; -b) bg=1 if [ -n "$command" ]; then Puke "options must precede arguments"; fi;; -i) input=1 if [ -n "$command" ]; then Puke "options must precede arguments"; fi;; -v) verbose=1 if [ -n "$command" ]; then Puke "options must precede arguments"; fi;; -e) errtoout=1 if [ -n "$command" ]; then Puke "options must precede arguments"; fi;; -o) if [ -n "$o_opt" ]; then Puke "specify only one -o option"; fi shift; o_opt="$1" if [ -n "$command" ]; then Puke "options must precede arguments"; fi;; -u) shift; user_prefix="$1@" if [ -n "$command" ]; then Puke "options must precede arguments"; fi;; -H) check_w_host=1 if [ -n "$command" ]; then Puke "options must precede arguments"; fi;; -Y) check_w_ypmatch=1 if [ -n "$command" ]; then Puke "options must precede arguments"; fi;; -P) check_w_ping=1 if [ -n "$command" ]; then Puke "options must precede arguments"; fi;; -*) Puke "$1 is not a valid option" ;; "") break;; *) hostlist="$hostlist $command"; command=$1;; esac shift done if [ -z "$command" ] then Puke "no command supplied" fi if [ -z "$hostlist" ] then Puke "no host(s) supplied" fi case "$user_prefix" in -*) Puke "no -u argument supplied" ;; esac if [ -n "$check_w_host" ] then for h in $hostlist do if host 2>&1 >/dev/null then Puke "host cannot find '$h'" fi done fi if [ -n "$check_w_ypmatch" ] then for h in $hostlist do if ypmatch hosts 2>&1 >/dev/null then Puke "ypmatch cannot find '$h'" fi done fi #-- OK, start doing useful things ---# # if [ -n "$input" ] then # read input! cat >$tmpfile # we can do away with the $tmpfile, with a fork for every host ... fi Ssh() { case "$errtoout" in "") ssh "$@" | sed "s/^/$h: /" ;; *) ssh "$@" 2>&1 | sed "s/^/$h: /" ;; esac } Ssh_o() { case "$o_opt" in "") Ssh "$@";; *) Ssh -o "$o_opt" "$@";; esac } Ssh_w_tmp() { if [ -f "$tmpfile" ] then cat $tmpfile | Ssh_o "$@" else Ssh_o -n "$@" fi } for h in $hostlist do if [ -z "$check_w_ping" ] || ping $h 2 >/dev/null # note: "2 >" # host is active then #if [ -z "`finger @$h 2>&1 | grep 'Connection refused$'`" ] # host accepts finger - very crude check to see if ssh will work # however, finger has been disabled since, where I live if true then if [ -n "$verbose" ] then echo "executing '$command' on '$h'" 1>&2 fi case "$bg" in "") Ssh_w_tmp $user_prefix$h "$command" ;; *) Ssh_w_tmp $user_prefix$h "$command" & ;; esac fi fi done rm -f $tmpfile