対話型CLIという名の悩み
シェルスクリプトを書いていて、途中でパスワードの入力を求められるコマンドに遭遇するのは、まさに苦痛です。完全に自動化したいのに、ツールが「yes/no」の確認やパスワード入力を待って停止してしまうからです。代表的な例としては、passwdコマンド、鍵認証を設定していないssh、あるいは数十年前のソフトウェアのインストーラーなどが挙げられます。
私が管理しているUbuntu 22.04(RAM 4GB)のサーバーでは、かつて、ある古いFTPバックアップツールのために、深夜2時に起きてパスワードを手入力しなければなりませんでした。そのツールは引数でのパスワード渡しをサポートしていなかったのです。毎晩数文字を打つために待機するのは、時間の凄まじい浪費でした。そこで出会ったのがexpectです。
なぜ一般的な方法では失敗するのか?
expectを使う前に、いくつか近道を試してみましたが、うまくいきませんでした。
- パイプの使用 (
echo "pass" | command): この方法はsudoやpasswdでは失敗することが多いです。理由は、これらのセキュリティツールがstdin(標準入力)を無視し、/dev/tty(端末デバイス)から直接読み取ろうとするためです。 - フラグの使用 (
-y):apt install -yなどは非常に便利です。しかし現実には、多くの社内スクリプトやレガシーソフトウェアには、そのような「寛容な」フラグは存在しません。
Expect:ユーザーの役割を演じるツール
Expectは単なるテクニックではなく、一つの独立したプログラムです。これは対話シナリオに基づいて動作します。「あなたがAと言ったら、私はBと答える」という仕組みです。
半年間実務で運用してみて、いくつかの核心的なポイントが見えてきました:
- メリット: あらゆる種類の対話を処理できます。分岐能力も非常に高く、「Error」が表示されたら終了し、「Success」なら続行するといった制御が可能です。特に、
autoexpectツールを使えば、スクリプトを自動生成することもできます。 - デメリット: Tcl(Tool Command Language)構文は、Bashに慣れた人には少し馴染みにくいかもしれません。また、ファイル内にパスワードをプレーンテキストで保存する場合のセキュリティリスクにも直面します。
インストールと基本コマンド
Ubuntu/Debianでは、わずか3秒でインストールが完了します。
sudo apt update && sudo apt install expect -y
expectのシナリオは、ほとんどの場合、以下の4つのコマンドを中心に構成されます:
spawn: プロセスを起動する(例:SSH接続を開始する)。expect: 画面に特定のキーワードが表示されるのを待機する。send: データを送り込む(キーボードで入力するのと同じ)。interact: 必要に応じて、制御権をユーザー(あなた)に戻す。
例1:パスワード変更を一瞬で自動化
passwdコマンドは通常、パスワードを2回入力させる必要があります。以下のchange_password.expスクリプトは、それをスマートに処理します。
#!/usr/bin/expect -f
set user [lindex $argv 0]
set password [lindex $argv 1]
spawn passwd $user
expect "Enter new UNIX password:"
send "$password\r"
expect "Retype new UNIX password:"
send "$password\r"
expect "password updated successfully"
expect eof
ヒント: send文字列の最後にある\rを忘れないでください。これはEnterキーを押す動作に相当します。これがないと、スクリプトは無期限に停止してしまいます。
例2:鍵認証がない環境でのSSHログイン
SSH鍵認証が標準ですが、古いネットワーク機器などでパスワードログインを強制される場合があります。その処理方法は以下の通りです。
#!/usr/bin/expect -f
set timeout 10
spawn ssh [email protected]
expect {
"yes/no" {
send "yes\r"
exp_continue
}
"password:" {
send "Secret123\r"
}
}
expect "$"
send "uptime\r"
send "exit\r"
expect eof
ここでは条件分岐構造を使用しています。サーバーがフィンガープリントの確認(yes/no)を求めてきた場合、スクリプトは「yes」と答え、次に「password」という行が表示されるまで待ち続けます。
Autoexpectの秘訣:コードを自動生成させる
スクリプトを手動で書くと、スペルミスが起きがちです。私はよくautoexpectを使って時間を80%節約しています。以下のコマンドを実行するだけです:
autoexpect ./your_script.sh
あとは、実際の人間と同じように操作してください。autoexpectがすべての操作を記録し、script.expというファイルに出力してくれます。あなたはそのファイルを開き、不要な部分を削除するだけで完了です。
セキュリティ上の注意:油断は禁物
ファイルにパスワードを保存するのは大きなリスクです。より安全に運用するために、私は常に以下の2つの鉄則を守っています:
- アクセス権限の制限:すぐに
chmod 600 script.expを実行してください。あなただけがこのファイルを読み取れるようにします。 - 環境変数の活用: パスワードをハードコードしないでください。HashiCorp Vaultのようなシークレット管理システムや、暗号化された環境変数からパスワードを渡すようにしましょう。
Expectを導入して以来、私のバックアップ作業は100%自動化され、入力ミスによるエラー率はゼロになりました。もしあなたが「扱いにくい」システムの管理に頭を悩ませているなら、Expectこそが退屈な深夜作業からあなたを救い出す武器になるはずです。

