本文目录导读:

我来详细讲解 Expect 自动化交互脚本的编写方法和常用模式。
基础结构
最简单的 Expect 脚本模板
#!/usr/bin/expect -f
# 设置超时时间
set timeout 10
# 启动程序
spawn ssh user@host
# 期待模式并发送响应
expect "password:" {
send "mypassword\r"
}
# 继续交互或退出
expect "$ "
send "ls -la\r"
# 等待命令完成
expect "$ "
# 结束交互
send "exit\r"
expect eof
关键命令详解
spawn - 启动进程
spawn ssh user@host spawn ftp ftp.example.com spawn telnet 192.168.1.1
expect - 等待模式匹配
# 基本用法
expect "pattern"
# 超时处理
expect {
"pattern1" { send "response1\r" }
"pattern2" { send "response2\r" }
timeout { puts "超时了"; exit 1 }
eof { puts "连接关闭"; exit }
}
# 全局匹配
expect -re {[Pp]assword:}
expect -exact "exact string"
send - 发送响应
send "command\r" # 发送命令并回车 send -- "password\r" # 发送以 - 开头的字符串 send -s "slow\r" # 缓慢发送
完整实例
SSH 自动登录和执行命令
#!/usr/bin/expect -f
# 定义变量
set host [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
set timeout 30
# 检查参数
if { $argc != 3 } {
puts "Usage: $argv0 host user password"
exit 1
}
# 启动 SSH
spawn ssh -o StrictHostKeyChecking=no $user@$host
# 处理认证
expect {
# 第一次连接时的主机密钥确认
"(yes/no)?" {
send "yes\r"
exp_continue
}
# 密码提示
"password:" {
send "$password\r"
exp_continue
}
# 登录成功后的提示符
-re {[$#] } {
puts "登录成功!"
}
timeout {
puts "连接超时"
exit 1
}
}
# 执行命令
send "uptime\r"
expect -re {[$#] }
send "who\r"
expect -re {[$#] }
# 退出
send "exit\r"
expect eof
puts "完成!"
交互式程序控制
#!/usr/bin/expect -f
# 自动配置程序
proc configure_app {password} {
spawn ./setup.sh
expect {
"Enter password:" {
send "$password\r"
exp_continue
}
"Confirm password:" {
send "$password\r"
exp_continue
}
"Choose option (1-5):" {
send "2\r"
exp_continue
}
"Continue? (y/n):" {
send "y\r"
exp_continue
}
"Installation complete" {
puts "安装完成"
}
timeout {
puts "安装超时"
exit 1
}
eof {
puts "程序结束"
}
}
}
configure_pass "mySecret123"
文件传输自动化
#!/usr/bin/expect -f
proc safe_ftp {host user password local_file remote_dir} {
spawn ftp $host
expect "Name (*):" {
send "$user\r"
}
expect "Password:" {
send "$password\r"
}
expect "ftp>" {
send "cd $remote_dir\r"
}
expect "ftp>" {
send "binary\r"
}
expect "ftp>" {
send "put $local_file\r"
}
expect {
-re {bytes sent in} {
puts "文件上传成功"
}
timeout {
puts "上传超时"
}
}
expect "ftp>" {
send "quit\r"
}
expect eof
}
safe_ftp "ftp.example.com" "user" "pass" "test.txt" "/uploads"
高级技巧
错误处理
#!/usr/bin/expect -f
proc ssh_with_retry {host user password {retry 3}} {
set count 0
while {$count < $retry} {
spawn ssh -o StrictHostKeyChecking=no $user@$host
expect {
"password:" {
send "$password\r"
expect {
-re {[$#] } {
puts "连接成功"
return 1
}
"Permission denied" {
puts "密码错误"
close
incr count
continue
}
timeout {
puts "登录超时"
close
incr count
continue
}
}
}
timeout {
puts "连接超时"
close
incr count
continue
}
eof {
puts "连接被拒绝"
close
incr count
continue
}
}
}
puts "重试次数用尽"
return 0
}
if {[ssh_with_retry "server.com" "admin" "pass123"]} {
send "ls -la\r"
expect -re {[$#] }
send "exit\r"
expect eof
}
多主机并行处理
#!/usr/bin/expect -f
proc process_host {host user password} {
spawn ssh $user@$host
expect "password:" {
send "$password\r"
}
expect -re {[$#] }
send "hostname\r"
expect -re {[$#] }
send "df -h\r"
expect -re {[$#] }
send "free -m\r"
expect -re {[$#] }
send "exit\r"
expect eof
}
# 从文件读取主机列表
set f [open "hosts.txt" r]
set timeout 20
while {[gets $f line] >= 0} {
set fields [split $line]
set host [lindex $fields 0]
set user [lindex $fields 1]
set pass [lindex $fields 2]
puts "处理主机: $host"
process_host $host $user $pass
}
close $f
日志记录
#!/usr/bin/expect -f
# 开启日志
log_file -a "expect_auto.log"
log_user 1 # 显示输出
spawn ssh user@host
expect "password:" {
send "mypassword\r"
}
# 记录到文件
set logfile [open "session.log" w]
expect_before {
-re {.*} {
puts $logfile $expect_out(buffer)
}
}
expect -re {[$#] }
send "cat /etc/passwd\r"
expect -re {[$#] }
close $logfile
send "exit\r"
expect eof
log_file
实战:自动化部署脚本
#!/usr/bin/expect -f
set timeout 30
set APP_DIR "/opt/myapp"
proc deploy {host user password version} {
spawn ssh $user@$host
expect "password:" {
send "$password\r"
}
expect -re {[$#] }
# 备份
send "sudo cp -r $APP_DIR ${APP_DIR}_backup_\$(date +%Y%m%d)\r"
expect "password for" {
send "$password\r"
}
expect -re {[$#] }
# 下载新版本
send "cd /tmp && wget http://repo.example.com/app-v${version}.tar.gz\r"
expect -re {[$#] }
# 解压并部署
send "tar -xzf app-v${version}.tar.gz -C $APP_DIR\r"
expect -re {[$#] }
# 重启服务
send "sudo systemctl restart myapp\r"
expect "password for" {
send "$password\r"
}
expect -re {[$#] }
# 检查状态
send "sudo systemctl status myapp\r"
expect -re {[$#] }
send "exit\r"
expect eof
puts "部署完成!版本: $version"
}
# 执行部署
if {$argc >= 3} {
deploy [lindex $argv 0] [lindex $argv 1] [lindex $argv 2] [lindex $argv 3]
} else {
puts "用法: ./deploy.tcl host user password version"
exit 1
}
常用模式和最佳实践
模式匹配技巧
# 模糊匹配
expect -gl {*password*}
expect -regexp {[Pp]ass(word|wd):}
# 匹配多个模式
expect {
"success" { do_success }
"failure" { do_failure }
"error" { do_error }
default { do_default }
}
# 时间相关的匹配
expect {
-timeout 5 "fast"
timeout { puts "等待超时" }
}
调试技巧
#!/usr/bin/expect -d # 开启调试模式 # 或者在脚本中开启 exp_internal 1 # 显示内部调试信息 # 手动控制输出 log_user 0 # 关闭输出 # ... 执行敏感操作 ... log_user 1 # 恢复输出
这些示例涵盖了 Expect 的主要用法,关键是要理解:
- 并行思维:处理可能出现的多种情况
- 适当超时:为每个操作设置合理的超时时间
- 错误处理:处理密码错误、连接超时等常见问题
- 安全性:避免在命令行直接暴露密码
根据你的具体需求调整这些模板即可。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播