expect 是基於 Tcl 的自動化互動工具,能處理需要密碼、確認提示的 CLI 程式 (ssh, scp, ftp, passwd 等),實現腳本化無人值守操作。本文從核心指令解析到三大實戰場景完整示範。
| 指令 | 功能 |
|---|---|
spawn cmd | 啟動子進程並建立管道 (expect 內部指令) |
expect "pattern" | 等待輸出匹配模式 (支援正則) |
send "string\r" | 發送字串 (需以 \r 結尾模擬 Enter) |
interact | 將控制權交還使用者 (保持互動) |
exp_continue | 繼續匹配下一個 expect 區塊 |
expect -re "regex" | 正則表達式匹配 |
expect eof | 等待子進程結束 |
#!/usr/bin/expect
set timeout 30
spawn ssh -l root 192.168.1.188
expect "password:"
send "abc123456\r"
interact
#!/usr/bin/expect -f
set timeout 30
spawn ssh -l root 192.168.1.188
expect {
"yes/no" { send "yes\r"; exp_continue }
"password:" { send "abc123456\r" }
}
expect -re "](#|\\$) "
send "bash /root/test.sh\r"
expect -re "](#|\\$) "
send "exit\r"
單行版 (嵌入 Bash 腳本):
#!/bin/bash
expect -c "
spawn ssh root@192.168.1.188 \"ifconfig; whoami; pwd; echo hello\"
expect {
\"*assword\" { send \"abc123456\r\" }
\"yes/no\" { send \"yes\r\"; exp_continue }
}
expect eof
"
主機清單 host.list:
192.168.1.1 22 root pass1
192.168.1.2 22 root pass2
192.168.1.3 22 root pass3
Expect 模組 main.exp:
#!/usr/bin/expect -f
set ipaddress [lindex $argv 0]
set port [lindex $argv 1]
set username [lindex $argv 2]
set passwd [lindex $argv 3]
set timeout 30
spawn ssh $ipaddress -p$port -l$username
expect {
"yes/no" { send "yes\r"; exp_continue }
"password:" { send "$passwd\r" }
}
expect -re "](#|\\$) "
send "bash /root/test.sh\r"
expect -re "](#|\\$) "
send "exit\r"
Bash 驅動迴圈 whi.sh:
#!/bin/bash
host="host.list"
while read line; do
expect main.exp $line
done < $host
expect -c "
spawn scp root@192.168.1.188:/root/file1.tgz /root
expect {
\"*assword\" { set timeout 300; send \"abc123456\r\" }
\"yes/no\" { send \"yes\r\"; exp_continue }
}
expect eof
"
ssh-copy-id) 取代 expect 密碼傳送chmod 700,限制擁有者讀寫catch 捕捉 spawn 失敗、連線逾時log_file -noappend session.log 記錄完整互動parallel-ssh、ansible 替代 expect 迴圈
| 工具 | 優點 | 缺點 |
|---|---|---|
| expect | 輕量、無依賴、支援任意 CLI 互動 | 明文密碼、維護困難、無冪等性 |
| Ansible | 冪等、模組豐富、YAML 可讀、並行 | 需 Python、學習曲線 |
expect 仍是快速解決舊系統、網路設備、無 Python 環境自動化互動的利器,但新架構建議優先採用 Ansible/SaltStack 等現代配置管理工具。