Expectの概要と用途
expect はTcl(Tool Command Language)をベースに開発されたツールであり、SSHやFTP、Telnetといった対話型プロンプトを必要とするCLIコマンドを自動化するために設計されています。複数のサーバーに対して同一の操作をバッチ処理する際、システム管理者の負荷を大幅に軽減し、運用効率を向上させます。
正規表現によるパターンマッチング機能を内蔵しており、プログラミング機能を持たないレガシーなCLIツールに対して柔軟な制御ロジックやマクロ機能をもたらすことができます。
環境構築とインストール
多くのLinuxディストリビューションではデフォルトでインストールされていないため、パッケージマネージャーを使用して導入します。以下はDebian/Ubuntu系システムでのインストールコマンドです。
sudo apt update
sudo apt install expect
主要な制御コマンドと構文
Expectスクリプトを構築する上で不可欠な基本コマンドは以下の通りです。
- spawn: 対話型プロセスを起動し、Expectの制御下に置きます。
- expect: プロセスの標準出力から特定の文字列を待ち受け、マッチング成功時に次のアクションを実行します。
- send: 制御下のプロセスに対して文字列(キー入力)を送信します。改行は
\rで表現します。 - interact: スクリプトによる自動制御を終了し、ユーザーの手動操作に制御権を移譲します。
- exp_continue: 現在の
expectブロック内で、次のパターンマッチング処理へループさせます。 - set timeout: 応答を待機するタイムアウト時間(秒)を設定します。
- send_user: シェル標準出力へメッセージを出力します(
echoと同等)。 - eof: プロセスの終了(End Of File)を検知します。
実践的なスクリプト例
1. 基本的なSSH自動ログイン
パスワード認証を要求するSSHセッションに自動でログインし、対話モードへ移行する基本スクリプトです。
#!/usr/bin/expect -f
set timeout 20
set target_ip "10.0.0.50"
set admin_user "deployer"
set auth_token "SecurePass123!"
spawn ssh ${admin_user}@${target_ip}
expect {
"password:" {
send "${auth_token}\r"
}
timeout {
puts "Connection timed out."
exit 1
}
}
interact
※スクリプトを実行可能にするためには chmod +x script.exp を実行するか、expect script.exp として実行します。
2. 複数パターンへの分岐処理
SSH接続時のフィンガープリント確認(yes/no)やパスワードプロンプトなど、複数の出力パターンに対して適切にレスポンスを返す構文です。
#!/usr/bin/expect -f
spawn ssh admin@192.168.1.100
expect {
"yes/no" {
send "yes\r"
exp_continue
}
"password:" {
send "MySecretPassword\r"
}
}
interact
3. 変数と位置引数の活用
スクリプト外部から引数を受け取り、動的に接続先を変更できるようにした汎用的なスクリプトです。
#!/usr/bin/expect -f
set db_host [lindex $argv 0]
set db_user [lindex $argv 1]
set db_pass [lindex $argv 2]
spawn mysql -h ${db_host} -u ${db_user} -p
expect "Enter password:"
send "${db_pass}\r"
expect "mysql>"
send "SHOW DATABASES;\r"
expect "mysql>"
send "exit\r"
expect eof
実行コマンド例: ./db_query.exp 10.0.0.5 root dbpassword
4. リモートサーバーでの複数コマンド実行
ログイン後に複数のコマンドを順次実行し、処理完了後にセッションを終了する自動化スクリプトです。
#!/usr/bin/expect -f
set srv_ip [lindex $argv 0]
set srv_user [lindex $argv 1]
set srv_pass [lindex $argv 2]
set timeout 15
spawn ssh ${srv_user}@${srv_ip}
expect {
"yes/no" { send "yes\r"; exp_continue }
"password:" { send "${srv_pass}\r" }
}
expect "~]$"
send "df -h\r"
expect "~]$"
send "free -m\r"
expect "~]$"
send "exit\r"
expect eof
5. Bashスクリプト内でのExpect呼び出し
Bashスクリプトの中でHere-Doc構文を使用してExpectをインライン実行する方法です。環境変数を介してBashの変数をExpectスクリプトに安全に渡すことができます。
#!/bin/bash
TARGET_HOST=$1
TARGET_USER=$2
TARGET_PASS=$3
# 環境変数としてエクスポートし、Expect側から参照可能にする
export TARGET_HOST TARGET_USER TARGET_PASS
/usr/bin/expect << 'EXPECT_SCRIPT'
set timeout 15
spawn ssh $env(TARGET_USER)@$env(TARGET_HOST)
expect {
"yes/no" { send "yes\r"; exp_continue }
"password:" { send "$env(TARGET_PASS)\r" }
}
expect "$ "
send "uptime\r"
expect "$ "
send "exit\r"
expect eof
EXPECT_SCRIPT