expect交互学习笔记
expect主要应用于自动化交互式操作的场景;比如服务器过多,密码也不尽相同的情况下,需要便捷的登陆服务器,而无需输入密码的情况,亦或者便捷登陆mysql/ftp等需要交互的场景;也可以在服务器之间通过scp传输文件而不需要输入密码的场景;
安装expect
CentOS:yum install expect -y
Mac:brew install expect
脚本后缀为exp
常用命令介绍
send 接收一个字符串,并将该字符串发送到进程;
expect 从进程接收字符串,根据进程反馈发送相应的交互命令,比如ssh登陆需要到输入密码的那步(password:);
spawn 启动新的进程,来执行相应的命令;
interact 允许用户交互,比如ssh登陆或者ftp登陆mysql登陆,加上interact参数则spawn启动的进程执行完成之后仍然停留在ssh/ftp/mysql的交互界面而不退出;
基本语法
1、方括号[cmd]
执行一个嵌套命令,例如想传递一个命令的结果作为另一个命令的参数则使用[ ];
2、双引号“ ”
$符在“ ”中仍然被解释,意思是可以进行变量替换;
puts "please enter number: $num"
3、设置变量
set name "zhang"
变量名name
4、输出使用puts
5、运算expr
expr $i/5
可以使用+ - * /和%作为基本运算符;还有一个运算符incr,表示对变量加1;
6、$argv 参数数组
通过 [lindex $argv n] 可以获得第 n 个参数的值
7、exp_continue
跟在某个 expect 判断项之后,可以使该项被匹配后,还能继续匹配该 expect 判断语句内的其他项,比如首次登陆Linux服务器需要先yes才能再输入密码,如果不加exp_continue则yes输入完成之后,会停在那,不再走输入密码的交互;
8、set timeout
设置超时时间,单位秒,假如配置为30,则某个 expect 判断未能成功匹配的 30 秒后,将跳过该 expect 判断,执行后续内容。可以设置为-1,表示无限制。
9、log_file
将expect在控制台的输出信息写入指定的文件中;
log_file out.log
常用参数
-d 用于跟踪脚本的执行过程,类似于shell脚本的bash -x效果;
-f 一般写在脚本最上面定义使用方法的时候才有用(#!/usr/bin/expect -f);实际作用尚不明确;
for循环
方法一:
#!/usr/bin/expect
foreach i { 1 2 3 4 5 } {
puts "$i"
}
方法二:
#!/usr/bin/expect
for {set i 0} {$i < 10} {incr i} {
puts "$i"
}
while循环
set i 0
while {$i < 10} {
puts "$i"
incr i
}
if语句
就拿我在实际应用中用的便捷登陆设备的脚本举例;在实际中我将该脚本的执行做成了别名的形式,运行的时候通过“别名 参数”的方式执行,很方便;
alias ai="/Users/zhangzhide/shen-project/ai-project.exp" #定义别名
ai 191 #通过别名登陆191这台设备
#!/usr/bin/expect
set timeout 2
set ip [lindex $argv 0]
set aixin221 "Password221"
set aixin191 "Password191"
if { $ip == 191 } {
spawn ssh root@100.13.0.$ip
expect {
"*yes/no*" { send "yes\r"; exp_continue }
"*password:" { send "$aixin191\r" }
}
interact
} elseif { $ip == 221 } {
spawn ssh root@100.13.0.$ip
expect {
"*yes/no*" { send "yes\r"; exp_continue }
"*password:" { send "$aixin221\r" }
}
interact
} else {
puts "please enter true ipaddr:
191 后端
221 前端页面"
}
函数
proc my_proc {i} {
puts $i;
}
在shell脚本中调用expect
#!/bin/bash
/usr/bin/expect << EOF
#在shell中调用expect
spawn ssh root@192.168.100.10
expect {
"*yes/no*" { send "yes\r"; exp_continue }
"*password*" { send "123\r" }
}
interact
EOF
scp传输举例
#!/usr/bin/expect set timeout 10 set host [lindex $argv 0] set username [lindex $argv 1] set password [lindex $argv 2] set src_file [lindex $argv 3] set dest_file [lindex $argv 4] spawn scp $src_file $username@$host:$dest_file expect { "*yes/no*" { send "yes\r"; exp_continue } "*password:" { send "$password\r" } } interact
执行脚本:/data/copy.exp 192.168.21.4 root 'wO0]Dcg;y' /data/m3u8.gz /data/m3u8.gz
注意:如果密码中包含特殊字符,需要用单引号引起来;
便捷登陆mysql举例
#!/usr/bin/expect
spawn mysql -h 10.10.0.36 -u root -p
expect "*password:"
send "123.com\r"
interact
批量导出mysql表结构应用
公司要搭一个新环境,需要用到老库的表结构,由于连接老库需要vpn,无法在CentOS服务器上通过mysqldump连接老库导表,只能通过个人电脑了,但是mac比较傲娇的是不支持(mysqldump -p PASSWD)直接将密码跟在-p参数后面的操作,50多个表啊,我不能一个一个的去输入密码,因此想到了expect;
具体操作方法如下:
1、先建立一个文件,将所有表名写入文件中;
vim table
table1
table2
...
table56
2、写expect脚本
#!/usr/bin/expect
set table [lindex $argv 0]
spawn mysqldump -h 10.10.0.23 -u root -p old_dat $table
expect "*password:"
send "123.com\r"
interact
3、用shell脚本调用expect脚本
for i in `cat table`;do echo `./table.exp $i > $i.sql`;done
这时候要问了,为什么不在expect中写for循环直接导出表呢?我这么尝试过,发现导不出来,后来查资料才知道spawn不支持标准输出;所以在expect脚本中无法实现,于是就想到了上面的方法,通过shell去调用expect脚本;由于时间紧,任务重,也就没管好不好看,好用就行;
注意:这么导出来的sql表仍然是不能用的,在导出的每个表中都会有一些额外的输出信息,好在它们在每个表中长得都一样,所以请出文本三剑客之一的sed批量处理一下就好啦;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· 因为Apifox不支持离线,我果断选择了Apipost!