脚本中Expect自动化交互如何写

wen 实用脚本 10

本文目录导读:

脚本中Expect自动化交互如何写

  1. 基础结构
  2. 关键命令详解
  3. 完整实例
  4. 高级技巧
  5. 实战:自动化部署脚本
  6. 常用模式和最佳实践

我来详细讲解 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 的主要用法,关键是要理解:

  1. 并行思维:处理可能出现的多种情况
  2. 适当超时:为每个操作设置合理的超时时间
  3. 错误处理:处理密码错误、连接超时等常见问题
  4. 安全性:避免在命令行直接暴露密码

根据你的具体需求调整这些模板即可。

抱歉,评论功能暂时关闭!