关于expect的实战总结
如何从机器A上ssh到机器B上,然后执行机器B上的命令?如何使之自动化完成?看完下面的文章你就明白了
一、安装
expect 是基于tcl 演变而来的,所以很多语法和tcl 类似
sudo apt-get install tcl tk expect
或者
yum install -y tcl tclx tcl-devel
二、如何使用
expect是linux中的一个用来处理交互的命令。借助Expect,我们可以将交互过程写在一个脚本上,使之自动化完成。形象的说,ssh登录,ftp登录等都符合交互的定义。下文我们首先提出一个问题,然后介绍基础知四个命令
四个命令
Expect中最关键的四个命令是send,expect,spawn,interact。
send:用于向进程发送字符串
expect:从进程接收字符串
spawn:启动新的进程
interact:允许用户交互
1、send
send命令接收一个字符串参数,并将该参数发送到进程。
expect1.1> send "hello world\n"
hello world
2. expect命令
启用选项
-c
:执行脚本前先执行的命令,可多次使用。-d
:debug模式,可以在运行时输出一些诊断信息,与在脚本开始处使用exp_internal 1
相似。-D
:启用交换调式器,可设一整数参数。-f
:从文件读取命令,仅用于使用#!时。如果文件名为"-",则从stdin读取(使用"./-"从文件名为-的文件读取)。-i
:交互式输入命令,使用"exit"或"EOF"退出输入状态。--
:标示选项结束(如果你需要传递与expect选项相似的参数给脚本时),可放到#!
行:#!/usr/bin/expect --
。-v
:显示expect版本信息。
expect命令和send命令正好相反,expect通常是用来等待一个进程的反馈。expect可以接收一个字符串参数,也可以接收正则表达式
expect "hi\n"
send "hello there!\n"
这两行代码的意思是:从标准输入中等到hi和换行键后,向标准输出输出hello there。
看一段代码:
#!/usr/bin/expect -f
expect "hi\n"
send "you typed <$expect_out(buffer)>"
send "but I only expected <$expect_out(0,string)>"
执行结果
1
2
3
4
5
hi
you typed <1
2
3
4
5
hi
>but I only expected <hi
多分支模式
expect "hi" { send "You said hi\n" } \
"hello" { send "Hello yourself\n" } \
"bye" { send "That was unexpected\n
或者下面的写法
expect {
"hi" { send "You said hi\n"}
"hello" { send "Hello yourself\n"}
"bye" { send "That was unexpected\n"}
}
3、spawn
spawn命令就是用来启动新的进程的,比如登录ftp
spawn ftp ftp.test.com
4、interact
interact ##是Expect用来打开用户与产生进程之间通信的命令,简单说就是登陆以后将远程服务器的终端保持在当前终端,而不是将远程终端关掉
#!/usr/bin/expect -f
set timeout -1
spawn ssh $user@$host
expect -exact "password"
send "$password\n"
send -- "pwd\n"
interacter
三、总结
1、常用命令
# 命令行参数
# $argv,参数数组,使用[lindex $argv n]获取,$argv 0为脚本名字
# $argc,参数个数
set username [lindex $argv 1] # 获取第1个参数
set passwd [lindex $argv 2] # 获取第2个参数 set timeout 30 # 设置超时 # spawn是expect内部命令,开启ssh连接
spawn ssh -l username 192.168.1.1 # 判断上次输出结果里是否包含“password:”的字符串,如果有则立即返回,否则就等待一段时间(timeout)后返回
expect "password:" # 发送内容ispass(密码、命令等)
send "ispass\r" # 发送内容给用户
send_user "$argv0 [lrange $argv 0 2]\n"
send_user "It's OK\r"
# 执行完成后保持交互状态,控制权交给控制台(手工操作)。否则会完成后会退出。
interact
2、命令介绍
- close:关闭当前进程的连接。
- debug:控制调试器。
- disconnect:断开进程连接(进程仍在后台运行)。
- 执行priv_prog:定时读取密码
- exit:退出expect。
- exp_continue [-continue_timer]:继续执行下面的匹配。
- exp_internal [-f file] value:
send_user "password?\ "
expect_user -re "(.*)\n"
for {} 1 {} {
if {[fork]!=0} {sleep 3600;continue}
disconnect
spawn priv_prog
expect Password:
send "$expect_out(1,string)\r"
. . .
exit
}
3、范例
A、自动telnet会话
#!/usr/bin/expect -f
set ip [lindex $argv 0 ] # 接收第1个参数,作为IP
set userid [lindex $argv 1 ] # 接收第2个参数,作为userid
set mypassword [lindex $argv 2 ] # 接收第3个参数,作为密码
set mycommand [lindex $argv 3 ] # 接收第4个参数,作为命令
set timeout 10 # 设置超时时间 # 向远程服务器请求打开一个telnet会话,并等待服务器询问用户名
spawn telnet $ip
expect "username:"
# 输入用户名,并等待服务器询问密码
send "$userid\r"
expect "password:"
# 输入密码,并等待键入需要运行的命令
send "$mypassword\r"
expect "%"
# 输入预先定好的密码,等待运行结果
send "$mycommand\r"
expect "%"
# 将运行结果存入到变量中,显示出来或者写到磁盘中
set results $expect_out(buffer)
# 退出telnet会话,等待服务器的退出提示EOF
send "exit\r"
expect eof
B、自动建立FTP会话
#!/usr/bin/expect -f
setip [lindex $argv 0 ] # 接收第1个参数,作为IP
setuserid [lindex $argv 1 ] # 接收第2个参数,作为Userid
setmypassword [lindex $argv 2 ] # 接收第3个参数,作为密码
settimeout 10 # 设置超时时间
# 向远程服务器请求打开一个FTP会话,并等待服务器询问用户名
spawn ftp$ip
expect "username:"
# 输入用户名,并等待服务器询问密码
send "$userid\r"
expect "password:"
# 输入密码,并等待FTP提示符的出现
send "$mypassword\r"
expect "ftp>"
# 切换到二进制模式,并等待FTP提示符的出现
send "bin\r"
expect "ftp>"
# 关闭ftp的提示符
send "prompt\r"
expect "ftp>"
# 下载所有文件
send "mget *\r"
expect "ftp>"
# 退出此次ftp会话,并等待服务器的退出提示EOF
send "bye\r"
expect eof
C、自动登录ssh执行命令
#!/usr/bin/expect
set IP [lindex $argv 0]
set USER [lindex $argv 1]
set PASSWD [lindex $argv 2]
set CMD [lindex $argv 3] spawn ssh $USER@$IP $CMD
expect {
"(yes/no)?" {
send "yes\r"
expect "password:"
send "$PASSWD\r"
}
"password:" {send "$PASSWD\r"}
"* to host" {exit 1}
}
expect eof
D、批量登录ssh服务器执行操作范例,设定增量的for循环
#!/usr/bin/expect
for {set i 10} {$i <= 12} {incr i} {
set timeout 30
set ssh_user [lindex $argv 0]
spawn ssh -i .ssh/$ssh_user abc$i.com expect_before "no)?" {
send "yes\r" }
sleep 1
expect "password*"
send "hello\r"
expect "*#"
send "echo hello expect! > /tmp/expect.txt\r"
expect "*#"
send "echo\r"
}
exit
E、批量登录ssh并执行命令,foreach语法
#!/usr/bin/expect
if {$argc!=2} {
send_user "usage: ./expect ssh_user password\n"
exit
}
foreach i {11 12} {
set timeout 30
set ssh_user [lindex $argv 0]
set password [lindex $argv 1]
spawn ssh -i .ssh/$ssh_user root@xxx.yy.com
expect_before "no)?" {
send "yes\r" }
sleep 1 expect "Enter passphrase for key*"
send "password\r"
expect "*#"
send "echo hello expect! > /tmp/expect.txt\r"
expect "*#"
send "echo\r"
}
exit
F、从命令行获取服务器IP,foreach语法,expect嵌套
#!/usr/bin/expect
# 使用方法: script_name ip1 ip2 ip3 ... set timeout 20
if {$argc < 1} {
puts "Usage: script IPs"
exit 1
}
# 替换你自己的用户名
set user "username"
#替换你自己的登录密码
set password "yourpassword" foreach IP $argv {
spawn ssh $user@$IP expect \
"(yes/no)?" {
send "yes\r"
expect "password:?" {
send "$password\r"
}
} "password:?" {
send "$password\r"
} expect "\$?"
# 替换你要执行的命令
send "last\r"
expect "\$?"
sleep 10
send "exit\r"
expect eof
}
G、ssh自动登录expect脚本
#!/usr/bin/expect -f
# Auther:YuanXing
# Update:2014-02-08
if {$argc < 4} {
send_user "Usage:\n $argv0 IPaddr User Passwd Port Passphrase\n"
puts stderr "argv error!\n"
sleep 1
exit 1
} set ip [lindex $argv 0 ]
set user [lindex $argv 1 ]
set passwd [lindex $argv 2 ]
set port [lindex $argv 3 ]
set passphrase [lindex $argv 4 ]
set timeout 6
if {$port == ""} {
set port 22
}
#send_user "IP:$ip,User:$user,Passwd:$passwd,Port:$port,Passphrase:$passphrase"
spawn ssh -p $port $user@$ip expect_before "(yes/no)\\?" {
send "yes\r"} expect \
"Enter passphrase for key*" {
send "$passphrase\r"
exp_continue
} " password:?" {
send "$passwd\r"
exp_continue
} "*\[#\\\$]" {
interact
} "* to host" {
send_user "Connect faild!"
exit 2
} timeout {
send_user "Connect timeout!"
exit 2
} eof {
send_user "Lost connect!"
exit
}
H、通过shell脚本调用
#!/bin/bash TMP=$(mktemp)
username=(test)
# create expect script for ip in `cat ip.txt`; do cat > $TMP << EOF
set timeout 5
spawn ssh -i $username/id_rsa -p888 $username@$ip expect -exact "$username"
send -- "su - \r\n" expect -exact "Password"
send -- "213f214##!ds(*&a@\r\n" expect -exact "root"
send -- "userdel -r zhangshan\r\n"
send -- "userdel -r lisi\r\n" send -- "history -c \r\n exit\r\n"
send -- "history -c \r\n exit\r\n"
expect eof EOF expect -f $TMP
rm $TMP
done
参考:
https://www.cnblogs.com/iloveyoucc/archive/2012/05/11/2496433.html
http://www.xuetimes.com/archives/781
关于expect的实战总结的更多相关文章
- Linux Shell 自动交互功能
需求背景: 近日,在安装某软件过程,发现在安装过程需要输入一些信息才能继续下一步操作,在机器数量较少情况下,我们可以单台登录上去完成安装操作,但当机器数量超过一定时,如果再手动登录操作,就会产生大 ...
- shell expect权威指南和实战
一.概述 我们通过Shell可以实现简单的控制流功能,如:循环.判断等.但是对于需要交互的场合则必须通过人工来干预,有时候我们可能会需要实现和交互程序如telnet服务器等进行交互的功能.而expec ...
- expect实战
1.测试主机是否在线 #!/bin/bash#创建一个IP地址文件.>ip.txt (清空文本)#使用for循环ping测试主机是否在线.for i in {2..254}do ...
- 【实战Java高并发程序设计 4】数组也能无锁:AtomicIntegerArray
除了提供基本数据类型外,JDK还为我们准备了数组等复合结构.当前可用的原子数组有:AtomicIntegerArray.AtomicLongArray和AtomicReferenceArray,分别表 ...
- 【实战Java高并发程序设计 1】Java中的指针:Unsafe类
是<实战Java高并发程序设计>第4章的几点. 如果你对技术有着不折不挠的追求,应该还会特别在意incrementAndGet() 方法中compareAndSet()的实现.现在,就让我 ...
- 【Java并发编程实战】-----“J.U.C”:Semaphore
信号量Semaphore是一个控制访问多个共享资源的计数器,它本质上是一个"共享锁". Java并发提供了两种加锁模式:共享锁和独占锁.前面LZ介绍的ReentrantLock就是 ...
- Selenium Web 自动化 - 项目实战(三)
Selenium Web 自动化 - 项目实战(三) 2016-08-10 目录 1 关键字驱动概述2 框架更改总览3 框架更改详解 3.1 解析新增页面目录 3.2 解析新增测试用例目录 3. ...
- Selenium2学习-016-WebUI自动化实战实例-014-Selenium 窗口选择
在日常的 WebUI 自动化测试脚本编写过程中,经常需要打开新的页面,或者在多个打开的页面之间进行切换,以对页面元素进行相应的操作,以模拟用户的行为,实现 UI 的自动化测试.在过往的时间中,经常有初 ...
- 60分钟内从零起步驾驭Hive实战学习笔记
本博文的主要内容是: 1. Hive本质解析 2. Hive安装实战 3. 使用Hive操作搜索引擎数据实战 SparkSQL前身是Shark,Shark强烈依赖于Hive.Spark原来没有做SQL ...
随机推荐
- Android Studio项目生成Jar包
步骤: 1)在module的gradle文件中,将apply plugin:'com.android.application'改为apply plugin:'com.android.library' ...
- SpringBoot整合dubbo
Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和Spring框架无缝集成. 以上介绍来源于百度百科,具体dubbo相关可以自行查 ...
- 设置 IntelliJ IDEA 智能提醒时忽略大小写
1.Ctrl + Alt + S 打开设置界面(或者从菜单File - settings 进来) 2.在搜索框输入Completion定位到Code Completion功能项 3.在右侧配置界面选中 ...
- BZOJ2948 : [Poi2001]绿色游戏
维护一个保护集合$S$,表示哪些点$A$可能胜利. 首先将所有绿点加入$S$. $1.$对于一个不在$S$的$A$点,若它存在某个后继在$S$中,则将其加入$S$. $2.$对于一个不在$S$的$B$ ...
- [P1373]小a和uim之大逃离 (DP)
[题目链接] 模拟赛的时候的一道题 因为老师不小心把数据发下来了……我考试打表的 考完之后Orz xzjds 然后开始打正解 题意 大概就是两个人,走矩阵,两个人各加上走上的矩阵的数值,要求最终两个人 ...
- c++ 引用犯的一个错
void cal(int * &a) { ................ } int main() { int x=1; int *p=x; cal( &x );//出错 cal( ...
- 关于setTimeout和setInterval的函数参数问题
今天在写验证码倒计时小demo时,用了如下代码: window.setTimeout(count(num),1000); 这样直接使用将使count函数立即执行,并将返回值传递给setTimeout函 ...
- 【贪心】[hdu1052]Tian Ji -- The Horse Racing(田忌赛马)[c++]
Tian Ji -- The Horse Racing Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java ...
- css冲刺
CSS知识点及面试题 1.一般与文本相关的属性都可以继承text-/font-/line- 2.background属性1)background-repeat:repeat/repeat-x/repe ...
- Spring mvc前台后台传值
前台向后台传值: ①同名参数传递:form表单中提交input,Controller方法入参中,直接以同名参数获取 ②不同名参数传递:from表单提交input,Controller方法入参中需要使用 ...