Kodama's home / tips.

複数のマシンでリモ−トでコマンド実行(expect, expect.rbの利用)

複数台のマシンに同じ作業を行いたい場合, rsh, rcp を使えば良い. rsh, rcp を使えない状況の場合, expect(1) か ruby(1) の expect.rb を用いて 自動的に telnet ,ftp, ssh や scp を実行すると良い. expect(1) は Tcl の拡張になっていて Tcl 風に使える. expect.rb は Ruby の IOクラスの拡張で expect 相当の機能を実現している. これらは Tcl や Ruby の拡張なので, 条件判断等の細工が可能になる.

以下のスクリプトを用いると, 複数の マシンに対する作業を 簡単におこなうことができる. 必要なのは EXP() の辺りの 10行程度であとは単なる飾りだ. 不要なら削り取ってしまおう. (このまま切り貼りして使う場合 "<" 記号に注意)

#!/bin/bash
# command.exp    Do command on remote hosts.
# takuji@kobe-kosen.ac.jp  1999 1st version
# kdm@kobe-kosen.ac.jp     1999.12

# set user, password and prompt
RUSER="guest" ;  RPASSWD="guest" ; RPROMPT="$ "

PROG="`basename $0`"
LOGFILE="$0.log"
#LOGFILE="/tmp/${PROG}.log"
#LOGFILE="/var/log/${PROG}.log"

HELP(){
if [ ! "$*" = "" ];then
   echo "$PROG: $*" >&2
   echo "`date`: $*" >> $LOGFILE
fi
cat << EOF
  Do command on remote hosts.
  Usage:
    $PROG [-h] host command , do command
    $PROG [-f] file command , read hosts from file
    $PROG -s command , read hosts from stdin
        Example: $PROG -s ls -l < hostlist
EOF
}

CHECKNUM(){ if [ "$#" -lt 2 ];then HELP "$*:Too few option." ; exit; fi }

ALIVE(){ ping -nqc1 "$1" >/dev/null 2>/dev/null }

EXP(){
    CHECKNUM "$@"; HOST="$1"; shift
    expect -c "
    set timeout 10
    spawn telnet $HOST
    expect login:\ ; send $RUSER\\r
    expect word:\ ; send \"$RPASSWD\r\"
    expect \"$RPROMPT\" ; send \"$*\r\"
    expect \"$RPROMPT\" ; send exit\\r
    "  & # Do expect as background
}


CHECKNUM "$@"

while getopts ":sh:f:" opt; do
  case $opt in
  h ) # -h host command
    if ALIVE "$OPTARG" ;then
        shift;CHECKNUM "$@"; EXP "$@"
    else
        HELP "$OPTARG: Cannot connect host."
    fi
    exit;;
  f ) # -f file 
    if [ -r "$OPTARG" ];then
        shift 2;CHECKNUM host "$@";xargs -i $0 -h \{} "$@" < $OPTARG
    else
        HELP "$OPTARG: File not found."
    fi
    exit;;
  s ) # -s read stdin
	shift;CHECKNUM host "$@";xargs -i $0 -h \{} "$@" ; exit;;
  \? )
       HELP "$*: option unknown." ;exit ;;
  esac
done


if [ -r "$1" ] && ALIVE "$1";then
    HELP "$1: Cannot determine file or host.";exit
elif ALIVE "$1" ;then
    # host command
    CHECKNUM "$@"; EXP "$@" ;exit
elif [ -r "$1" ];then
	FILE=$1;shift;CHECKNUM host "$@";xargs -i $0 -h \{} "$@" < $FILE ; exit
else
    HELP "$1: Cannot find host/file."; exit
fi
# end of script

Kodama's home / tips.