expectコマンドでLinuxの対話型処理を自動化する方法|パスワード入力・SSHログイン・telnetの自動操作実践例

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Linuxtips, シェルスクリプト > expectコマンドでLinuxの対話型処理を自動化する方法|パスワード入力・SSHログイン・telnetの自動操作実践例
「パスワードを手動で入力しないとスクリプトが進まない……自動化できないのか?」
ssh-keygen や sudo passwd など、対話的に応答を求めてくるコマンドは、通常のシェルスクリプトでは自動化が難しい。sshpass は使えても、複数の質問に順番に答えるような複雑な対話は手に負えなかったりする。

この記事では、対話型コマンドを自動化するためのツール expect の実践的な使い方を解説する。基本構文から、SSHログイン自動化、パスワード変更スクリプト、タイムアウト処理まで、現場で実際に使えるパターンを紹介する。
動作確認環境: RHEL 9.4 / Ubuntu 24.04 LTS

この記事のポイント

expectspawn(起動)・expect(待機)・send(入力)の3コマンドで構成される
・SSHのパスワード入力やsudo対話を完全無人化できるが、鍵認証の方が安全でシンプル
spawn -noecholog_user 0 でパスワードをターミナルに表示しないよう制御できる
expect_background ではなく exp_continue でループを回すのが実践の定番パターン


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

expectとは何か(仕組みと使いどころ)

expect は Tcl(Tool Command Language)を拡張したスクリプト言語で、対話型プログラムとの「会話」を自動化するツールだ。

通常のシェルスクリプトは「コマンドを実行してその結果を処理する」ことが得意だが、プログラムが「何かを要求してくるまで待つ」という対話的な動作は苦手だ。expect はこの問題を解決する。

主な用途はこのようなケースだ。

・SSHログイン時のパスワード入力を自動化する(鍵認証が使えない環境)
passwdadduser の対話プロンプトに自動応答する
・古いネットワーク機器へのtelnetログインを自動化する
・FTPクライアントのコマンド操作を自動化する

1. expectのインストール

# RHEL / AlmaLinux / Rocky Linux $ sudo dnf install expect # Ubuntu / Debian $ sudo apt install expect # バージョン確認 $ expect -v expect version 5.45.4

基本的な使い方(spawn・expect・send)

expectスクリプトは3つのコア命令で構成される。

spawn:自動化したいコマンドを子プロセスとして起動する
expect:子プロセスの出力から特定の文字列が来るまで待機する
send:子プロセスに文字列を送信する(\r でEnterキーを表す)

1. 最もシンプルなexpectスクリプト(helloworld)

#!/usr/bin/expect # 最小構成のexpectスクリプト # 子プロセスを起動する spawn /bin/bash # "$ " というプロンプトが来るまで待つ expect "$ " # コマンドを送信する(\r はEnterキー) send "echo 'Hello from expect'\r" # 再びプロンプトが来るまで待つ expect "$ " # スクリプトを終了する send "exit\r" expect eof

2. スクリプトに実行権限を付けて実行する

$ chmod +x hello.exp $ ./hello.exp spawn /bin/bash [server01 ~]$ echo 'Hello from expect' Hello from expect [server01 ~]$ exit

3. タイムアウトを設定する(timeout)

expect はデフォルト10秒待機する。応答が来ない場合の動作をコントロールするにはタイムアウト設定が必要だ。

#!/usr/bin/expect # タイムアウトを30秒に設定する(デフォルト10秒) set timeout 30 spawn ssh user@192.168.1.100 # パスワードプロンプトが30秒以内に来ない場合はタイムアウト expect { "password:" { send "mypassword\r" } timeout { puts "タイムアウト: 接続に失敗しました" exit 1 } } expect "$ " send "hostname\r" expect "$ " send "exit\r" expect eof

SSHログインの自動化

1. パスワード認証でSSHログインして操作する

#!/usr/bin/expect # ssh-login.exp: SSHログインとコマンド実行を自動化する set host [lindex $argv 0] # 第1引数: ホスト名またはIPアドレス set user [lindex $argv 1] # 第2引数: ユーザー名 set password [lindex $argv 2] # 第3引数: パスワード(後述の安全対策を参照) set timeout 20 # SSH接続を起動する(known_hosts確認を自動でyes) spawn ssh -o StrictHostKeyChecking=no ${user}@${host} # パスワードプロンプトを待つ expect { "password:" { send "${password}\r" } "Are you sure you want to continue connecting" { send "yes\r" expect "password:" send "${password}\r" } timeout { puts "エラー: SSH接続タイムアウト" exit 1 } } # ログイン後のプロンプトを待つ expect "$ " # 実行するコマンド send "df -h\r" expect "$ " send "free -h\r" expect "$ " send "exit\r" expect eof puts "SSH操作が完了しました"

実行結果(実サーバー):

[local@client ~]$ ./ssh-login.exp 192.168.1.100 tomohiro 'P@ssw0rd' spawn ssh -o StrictHostKeyChecking=no tomohiro@192.168.1.100 tomohiro@192.168.1.100's password: Last login: Sun Jun 22 14:00:00 2026 from 192.168.1.50 [tomohiro@server01 ~]$ df -h Filesystem Size Used Avail Use% Mounted on /dev/sda1 50G 12G 38G 24% / ... SSH操作が完了しました

2. ホストフィンガープリントの確認をスキップする(注意点)

StrictHostKeyChecking=no はMITM攻撃のリスクを高めるため、本番環境では注意が必要だ。既知ホストへの接続なら、事前に ssh-keyscanknown_hosts に追加しておく方が安全だ。

# 事前にknown_hostsに追加する $ ssh-keyscan -H 192.168.1.100 >> ~/.ssh/known_hosts # 追加後はStrictHostKeyChecking=noなしで接続できる spawn ssh ${user}@${host}

sudoを使ったroot権限コマンドの自動化

1. sudoパスワードを自動入力する

#!/usr/bin/expect # sudo-auto.exp: sudoの対話を自動化する set sudo_pass "mysudopassword" set timeout 15 spawn bash -c "sudo systemctl restart nginx" expect { "\[sudo\] password for" { send "${sudo_pass}\r" } "password:" { send "${sudo_pass}\r" } eof { # パスワード不要のsudoers設定の場合はここに到達 } timeout { puts "タイムアウト" exit 1 } } expect { eof { puts "nginxの再起動が完了しました" } timeout { puts "コマンド実行タイムアウト" exit 1 } }

passwdコマンドの自動化(パスワード変更)

1. ユーザーパスワードを自動設定する

#!/usr/bin/expect # change-passwd.exp: passwdコマンドの対話を自動化する set username [lindex $argv 0] set newpass [lindex $argv 1] set timeout 15 spawn sudo passwd $username expect "New password:" send "${newpass}\r" expect "Retype new password:" send "${newpass}\r" expect { "passwd: password updated successfully" { puts "パスワードの変更が完了しました" exit 0 } "BAD PASSWORD" { puts "エラー: パスワードがポリシーを満たしていません" exit 1 } timeout { puts "タイムアウト" exit 1 } }

# 実行例 $ ./change-passwd.exp testuser 'NewP@ss2026' spawn sudo passwd testuser New password: Retype new password: passwd: password updated successfully パスワードの変更が完了しました

exp_continueでループ処理を行う

複数の選択肢に対して繰り返し対応するには exp_continue を使う。これはexpectブロックを再度実行する命令で、繰り返し出てくるプロンプトへの対応に使う。

#!/usr/bin/expect # expect-loop.exp: 複数のプロンプトに順番に対応する set timeout 30 spawn ftp ftp.example.com expect { "Name " { send "anonymous\r" exp_continue } "Password:" { send "anonymous@example.com\r" exp_continue } "ftp> " { # ログイン成功 send "ls\r" } timeout { puts "接続タイムアウト" exit 1 } } expect "ftp> " send "quit\r" expect eof

セキュリティ上の注意点

expectはパスワードをスクリプト内に平文で記述するケースが多く、セキュリティリスクがある。本番環境での使用前に以下を必ず確認すること。

スクリプトのパーミッション:パスワードを含むスクリプトは chmod 700 でオーナーのみ実行可能にする
環境変数でパスワードを渡す:スクリプト内にハードコードするより $env(SSH_PASS) で参照する方がgitへの誤コミットを防げる
expect vs 鍵認証:SSHの自動化は原則として公開鍵認証を使うべきだ。expectによるパスワード自動化は鍵認証が使えない古いシステムや制約のある環境に限定する

# 環境変数でパスワードを渡す例(スクリプト側) set password $env(MY_SSH_PASS) # 実行側 $ export MY_SSH_PASS='P@ssw0rd' $ ./ssh-login.exp 192.168.1.100 tomohiro

トラブルシュート・よくある問題

1. expect: command not found

expectがインストールされていない。dnf install expect または apt install expect でインストールする。

2. プロンプトが一致しない(ログイン後に止まる)

expect で待つ文字列がサーバー環境によって異なる場合に起きる。interact コマンドや log_user 1 で実際の出力を確認してプロンプト文字列を調整する。

# デバッグ: 出力を全て表示する log_user 1 # 正規表現でプロンプトにマッチさせる(汎用的) expect -re "\\\$\s*$" expect -re "#\s*$"

3. パスワードがターミナルに表示される

send した文字列はデフォルトでターミナルにエコーされる。ログに残したくない場合は log_user 0 で出力を抑制する。

expect "password:" log_user 0 # エコーを無効化 send "${password}\r" log_user 1 # エコーを元に戻す

本記事のまとめ

やりたいこと expectの書き方
コマンドを子プロセスで起動する spawn コマンド
特定の文字列が来るまで待つ expect "文字列"
文字列を送信する(Enter込み) send "入力\r"
複数パターンに分岐する expect { "A" { } "B" { } }
expectブロックを繰り返す exp_continue
タイムアウトを設定する set timeout 30
出力を画面に表示しない log_user 0
プロセス終了まで待つ expect eof
expect は「古いシステムとの対話を自動化する最後の手段」として現場で今も活躍する。鍵認証やAPIが使えるなら迷わずそちらを選ぶべきだが、レガシーなネットワーク機器や制約のある環境では expect が唯一の自動化手段になる。まずは最小構成の spawn → expect → send → expect eof パターンから始めてほしい。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、
Linux Master Pro Seminar(2日間ハンズオン)では AlmaLinux・Rocky Linux・RHEL対応の本番サーバー設計から運用まで、
実際のサーバーを触りながら習得できます。

>> セミナー詳細・お申込みはこちら

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。