关于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
- 作者:踏雪无痕
- 出处:http://www.cnblogs.com/chenpingzhao/
- 本文版权归作者和博客园共有,如需转载,请联系 pingzhao1990#163.com