expect のメモ
expect は、LANスイッチやサーバなどに自動接続してアレコレするのに便利なスクリプト。
expect の基本形
以下、ssh で接続して接続先で適当なコマンドを発行する例。
spawn して expect, send の繰り返しのため、サブルーチン化したい。
sample1.ex
#!/usr/bin/expect
set timeout 5
spawn env LANG=C ssh user@192.168.0.10
expect "assword:" { send "userpass\r" }
expect "\\\$"
send "echo hello\r" ; # 任意のコマンド実行例1
expect "\\\$"
send "pwd\r" ; # 任意のコマンド実行例2
interact
expectとsend をサブルーチン化(-> OK)
spawn 後の expect と send は基本的に対で実行するため、proc で
サブルーチン化すると連続したコマンド発行を(見た目)簡素化できる。
sample2.ex
#!/usr/bin/expect
set timeout 5
proc SENDS { data } { ; # <---- サブルーチン化
expect "\\\$"
send "$data\r"
}
spawn env LANG=C ssh user@192.168.0.10
expect "assword:" { send "userpass\r" }
SENDS "echo hello"
SENDS "pwd"
interact
結果
$ ./sample2.ex
spawn env LANG=C ssh user@192.168.0.10
user@192.168.0.10's password:
Last login: Sun Jan 29 01:53:32 2023 from mypc
$ echo hello
hello
$ pwd
/home/user
spawn をサブルーチン化(-> NG)
上記の例に続けて、spawn もサブルーチン化すると期待通りの動作をしない。
expect -d で見ると、spawn_proc の spawn で生成されたプロセスID である spawn_id が
spawn_proc 外で参照できない局所的な値のためらしい。
sample3.ex
#!/usr/bin/expect
set timeout 5
proc SENDS { data } {
expect "\\\$"
send "$data\r"
}
proc spawn_proc { } { ; # <---- サブルーチン化
spawn env LANG=C ssh user@192.168.0.10
expect "assword:" { send "userpass\r" }
SENDS "echo hello"
SENDS "pwd"
interact
}
spawn_proc ; # <---- spawn 呼び出し
結果
$ ./sample3.ex
spawn env LANG=C ssh user@192.168.0.10
user@192.168.0.10's password: echo hello <---sendが正しく動作していない
Last login: Sun Jan 29 01:59:16 2023 from mypc
spawn_id を send に渡す(-> OK)
spawn_id を別のサブルーチンに引数で渡し、受けた側は expect -i
と send -i
で使う。
sample4.ex
#!/usr/bin/expect
set timeout 5
proc SENDS { sid data } { ; # <---- 引数で受け取る
expect -i $sid "\\\$" ; # <---- -i オプション
send -i $sid "$data\r" ; # <---- -i オプション
}
proc spawn_proc { } {
spawn env LANG=C ssh user@192.168.0.10
expect "assword:" { send "userpass\r" }
SENDS $spawn_id "echo hello" ; # <---- 引数で渡す
SENDS $spawn_id "pwd" ; # <---- 引数で渡す
interact
}
spawn_proc
これは期待動作する。
spawn_id を global 宣言する(-> OK)
spawn をサブルーチン化する proc で global spawn_id
する。
sample5.ex
#!/usr/bin/expect
set timeout 5
proc SENDS { data } {
expect "\\\$"
send "$data\r"
}
proc spawn_proc { } {
global spawn_id ; # <---- 追加
spawn env LANG=C ssh user@192.168.0.10
expect "assword:" { send "userpass\r" }
SENDS "echo hello"
SENDS "pwd"
interact
}
spawn_proc
同じく動作する。SENDS 側は global spanw_id
しなくていい。