Kodama's home / tips.

expect. 対話的なコマンド(ssh, telnet, ftp, su等)を自動実行したいとき

ssh, telnet , ftp 等の対話的に使用するように作られたプログラムを スクリプト中に組み込んで定型的な作業を自動実行したい場合には expect を用いる事をお勧めします. また, ruby 言語を使えるなら ruby の expect.rb を使うのも良いでしょう. スクリプト中で su が必要な作業をさせたい場合にも便利です.

複数のマシンでの管理作業に利用した例があります. 複数のマシンでリモ−トでコマンド実行

手作業での実行例

次は telnet して ls する場面です.

$ telnet hoge       # マシンhoge に telnet した
hoge login: foo     # ログイン名 foo 
Password:           # パスワ−ドを入力した
hoge:~$ ls          # リストを取る
...
hoge:~$ exit        # 作業終了
logout
Connection closed by foreign host.
$
これを expect で自動化してみます. 上の手作業での手順をなぞっているのが分かると思います. expect と send に注目して下さい.

expect で telnet する例

#!/bin/sh                 # shell スクリプトにしてみた 

H=hoge                 # telnet するマシン名を設定
U=foo                 # ログイン名を設定
PW=******             # パスワ−ドを設定

expect -c "               # expect コマンドを実行
set timeout 20
spawn telnet $H        # expect コマンドの管理下でtelnetを実行する
expect login:\  ; send \"$U\r\"     # login: が出たらログイン名を打ち込む
expect sword:\  ; send \"$PW\r\"    # password: が出たらパスワ−ドを打ち込む
expect \"$ \" ; send \"ls\r\"            # $ が出たら ls を打ち込む
expect \"$ \" ; send \"exit\r\"          # $ が出たら exit を打ち込む
"

expect で ssh する例

上記の実行を shell 関数化して再利用可能にし, ssh でのログインに変えてみました. "$" 記号がいくつかの異る意味で使用されているので注意が必要です.
#!/bin/sh

X_CMD(){ # user pw host cmd ##  ssh ログインしてコマンドを実行するshell関数
	local U=$1 ; shift # user
	local PW=$1 ; shift # password
	local H=$1 ; shift # host
	local PR='(#|\\$) $'  # prompt regular expression
	expect -c "
    set timeout 20
    spawn ssh -l $U $H
    while (1) { 
      expect timeout { break } \"(yes/no)?\" { sleep 1;send \"yes\r\" } \"word: \" { sleep 1;send \"$PW\r\" } -re \"$PR\" { sleep 1;send \"\r\";break }
    }
    expect -re \"$PR\" ; sleep 1; send \"$*\r\"
    expect -re \"$PR\" ; sleep 1; send \"exit\r\"
    "
}

RUSER="my-name" ;  RPASSWD="my-pass" ; HOST=hoge # remote user and password

X_CMD $RUSER $RPASSWD $HOST ls /home # ls する
X_CMD $RUSER $RPASSWD $HOST "cd /home;ls" # cd して ls する

Kodama's home / tips.