我们经常会遇到一些需要与服务器程序打交道的场景,比如,从登陆某个服务器,然后进行某项工作。这很平常,但是如果把这个工作自动化进行,你就需要一个程序能自动做你要告诉机器的事情,这样,我们的expect就能大显身手了。

首先,expect是一个简单的工具语言,如要工作就是进行自动化的人机交互。它的作者对Expect的定义:是一个实现自动交互功能的软件套件(a software suite for automating interactive tools),使用expect,它能帮助我们在合适的情景下进行合适的交互。

例子:我们要在凌晨登陆到一个linux服务器:192.168.1.1,然后执行一个命令做/home/test/a.sh,我们的思路是:写一个expect脚本,然后用crontab在凌晨运行。

    #!/usr/bin/expect -f
set timeout 30
spawn ssh -l test 192.168.1.1
expect "password:"
send "mypassword\r"
expect "~$*"
send "/home/test/a.sh\r"
send "exit\n"
expect eof
exit

expect 的核心功能,对于设定好的特定匹配形式,以相匹配的动作以应对。每一个expect后所跟的字符串(或者正则表达式)就是脚本所等待的匹配模式,每一个send 所做的工作就是对于各种的模式串,实施相应的动作。

第一行设定了脚本执行的程序,-f选项指的是expect执行一个文件

第二行,设定了本脚本所有的超时时间,单位是秒(s),如果超时,脚本将继续向下进行(比如在等待某个模式出现,超时以后,会进行下一语句)。

第三行,expect使用spawn命令来启动脚本和命令会话,这里启动的是ssh命令,这里的ssh命令将会以子进程的方式产生。

下面就是交互的过程:ssh -l 登陆以后,会给要求客户写入密码,所以等待出现“password:”,出现password:以后,需要写入密码,注意这里需要送去回车或者换行符,否则远端主机不会收到ssh请求的。登陆上系统之后,会出现命令提示符:~$,即系统已经登陆到了远端主机的shell,然后送去要执行的命令。完毕后推出远程机器(这个send "exit\r"前也可以有上一个命令的输出,也可以没有,因为上一个命令执行完毕后会顺序执行下一条)。

最后是等待标示子进程已结束的标示符eof,然后退出。(注:这个等待eof必须要有,如果没有eof,很可能在子进程没有结束前就退出,造成问题。)

下面的例子,介绍expect其他重要的命令,先看如下例子:

    #!/usr/bin/expect -f
set timeout 10
set myname [lindex $argv 0]
spawn ./talk.sh
expect "Name:"
send "$myname\r"
expect eof

这个例子引入了输入参数的概念,就是在执行这个expect脚本时候,需要带入参数,比如这个脚本名字如果为test.ep

执行时需要键入参数:./test.ep "John"

set myname [lindex $argv 0] 这句获取外部传入的第一个参数(argv 0)并传给变量myname,如果获取多个参数则使用argv 1,argv 2,以此类推。

另外,expect支持一般语言所常用的if,for等流程控制语句,这个可以参看expect高级介绍

小结:

expect是一款非常好用的自动化交互工具

核心命令:

spawn: 启动一个命令或程序,并由expect程序开始监听

set :设置变量值和名称

set .. lindex:从程序输入参数出获取变量值并赋给变量

expect ...send对:expect等待希望出现的匹配串,对于匹配到的串,send发送命令进行执行。

如何向expect脚本里面传递参数

比如下面脚本用来做ssh无密码登陆,自动输入确认yes和密码信息,用户名,密码,hostname通过参数来传递
 
ssh.exp
Python代码  
#!/usr/bin/expect
set timeout 10
set username [lindex $argv 0]
set password [lindex $argv 1]
set hostname [lindex $argv 2]
spawn ssh-copy-id -i .ssh/id_rsa.pub $username@$hostname
expect "yes/no"
send "yes\r"
expect "password:"
send "$password\r"
expect eof
执行脚本./ssh.exp root pasword hostname1
expect接收参数的方式和bash脚本的方式不太一样,bash是通过$0 ... $n 这种方式,而expect是通过set <变量名称> [lindex $argv <param index>],例如set username [lindex $argv 0]
 

expect用法

1. [#!/usr/bin/expect]

这一行告诉操作系统脚本里的代码使用那一个shell来执行。这里的expect其实和linux下的bash、windows下的cmd是一类东西。

注意:这一行需要在脚本的第一行。

2. [set timeout 30]

基本上认识英文的都知道这是设置超时时间的,现在你只要记住他的计时单位是:秒   。timeout -1 为永不超时

3. [spawn ssh -l username 192.168.1.1]

spawn是进入expect环境后才可以执行的expect内部命令,如果没有装expect或者直接在默认的SHELL下执行是找 不到spawn命令的。所以不要用 “which spawn“之类的命令去找spawn命令。好比windows里的dir就是一个内部命令,这个命令由shell自带,你无法找到一个dir.com 或 dir.exe 的可执行文件。

它主要的功能是给ssh运行进程加个壳,用来传递交互指令。

4. [expect "password:"]

这里的expect也是expect的一个内部命令,有点晕吧,expect的shell命令和内部命令是一样的,但不是一个功能,习 惯就好了。这个命令的意思是判断上次输出结果里是否包含“password:”的字符串,如果有则立即返回,否则就等待一段时间后返回,这里等待时长就是 前面设置的30秒

5. [send "ispass\r"]

这里就是执行交互动作,与手工输入密码的动作等效。

温馨提示: 命令字符串结尾别忘记加上“\r”,如果出现异常等待的状态可以核查一下。

6. [interact]

执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上。如果你只是登录过去执行

7.$argv 参数数组

expect脚本可以接受从bash传递过来的参数.可以使用[lindex $argv n]获得,n从0开始,分别表示第一个,第二个,第三个....参数

下面的expect脚本的例子

执行这个文件./launch.exp 1 2 3

屏幕上就会分别打印出参数

send_user用来发送内容给用户。

参数运用方面还有很多技巧

比如$argc 存储了参数个数,args被结构化成一个列表存在argv。$argv0 被初始化为脚本名字。

除此之外,如果你在第一行(#!那行)使用-d (debug参数),可以在运行的时候输出一些很有用的信息

比如你会看见

argv[0] = /usr/bin/expect argv[1] = -d argv[2] = ./launch.exp argv[3] = 1 argv[4] = 2 argv[5] = 3

使用这些也可以完成参数传递

8.

expect的命令行参数参考了c语言的,与bash shell有点不一样。其中,$argc为命令行参数的个数,$argv0为脚本名字本身,$argv为命令行参数。[lrange $argv 0 0]表示第1个参数,[lrange $argv 0 4]为第一个到第五个参数。与c语言不一样的地方在于,$argv不包含脚本名字本身。

9. exp_continue的用法

#!/usr/bin/expect -f

set ipaddr "localhost"

set passwd "iforgot"

spawn ssh root@$ipaddr              #spawn   意思是执行命令,expect内命令,shell中不存在

expect {

"yes/no" { send "yes\r"; exp_continue}

"password:" { send "$passwd\r" }

}

expect "]# "

send "touch a.txt\r"                       #意思为发送命令

send "exit\r"

expect eof

exit

exp_continue可以继续执行下面的匹配,简单了许多。还有一点,让我认识到匹配不见得要匹配最后几个字符。

10.拿来小例子

设置变量     set PASSWD   abcd123

#!/usr/bin/expect -f

# Expect script to supply root/admin password for remote ssh server

# and execute command.

# This script needs three argument to(s) connect to remote server:

# password = Password of remote UNIX server, for root user.

# ipaddr = IP Addreess of remote UNIX server, no hostname

# scriptname = Path to remote script which will execute on remote server

# If you username and passwd has not pass the rsa trust, your login will fail.

# Usage For example:

#  ./sshlogin.exp password 192.168.1.11 who

# ------------------------------------------------------------------------

# Copyright (c) 2004 nixCraft project <http://cyberciti.biz/fb/>

# This script is licensed under GNU GPL version 2.0 or above

# -------------------------------------------------------------------------

# This script is part of nixCraft shell script collection (NSSC)

# Visit http://bash.cyberciti.biz/ for more information.

# ----------------------------------------------------------------------

# set Variables

set password [lrange $argv 0 0]

set ipaddr [lrange $argv 1 1]

set scriptname [lrange $argv 2 2]

set arg1 [lrange $argv 3 3]

set timeout -1

# now connect to remote UNIX box (ipaddr) with given script to execute

spawn ssh yourusername@$ipaddr $scriptname $arg1

match_max 100000

# Look for passwod prompt

expect "*?assword:*"

# Send password aka $password

send -- "$password\r"

# send blank line (\r) to make sure we get back to gui

send -- "\r"

expect eof
 
#!/usr/bin/expect 

 # 设置超时时间为 60 秒

 set timeout  60                                         

 # 设置要登录的主机 IP 地址

 set host 192.168.1.46

 # 设置以什么名字的用户登录

 set name root 

 # 设置用户名的登录密码

 set password 123456 

 #spawn 一个 ssh 登录进程

 spawn  ssh $host -l $name 

 # 等待响应,第一次登录往往会提示是否永久保存 RSA 到本机的 know hosts 列表中;等到回答后,在提示输出密码;之后就直接提示输入密码

 expect { 

    "(yes/no)?" { 

        send "yes\n"

        expect "assword:"

        send "$pasword\n"

    } 

        "assword:" { 

        send "$password\n"

    } 

 } 

 expect "#"

 # 下面测试是否登录到 $host 

 send "uname\n"

 expect "Linux"

 send_user  "Now you can do some operation on this terminal\n"

 # 这里使用了 interact 命令,使执行完程序后,用户可以在 $host 终端进行交互操作。

 Interact

用expect实现ssh自动登录对服务器进行批量管理

1.实现ssh自动登录完成任务的expect脚本

#!/usr/bin/expect -f

set ipaddress [lindex $argv 0]

set passwd [lindex $argv 1]

set timeout 30

spawn ssh shellqun@$ipaddress

expect {

"yes/no" { send "yes\r";exp_continue }

"password:" { send "$passwd\r" }

}

expect "*from*"

send "mkdir -p ./tmp/testfile\r"

#send "exit\r"

expect "#"  命令运行完, 你要期待一个结果, 结果就是返回shell提示符了(是# 或者$)

#最后一句第13行的解释:

其实写成 interact 的最大好处是登录后不会退出,而会一直保持会话连接,可以后续手动处理其它任务,请根据实际情况自行选择了。

2.调用login.exp完成批量管理

#!/bin/bash

for i in `awk '{print $1}' passwd.txt`

do

j=`awk -v I="$i" '{if(I==$1)print $2}' passwd.txt`

expect /root/shell/login.exp $i $j

done

linux下的expect的简单用法及举例

1、使用expect前,需要先安装两个rpm包,下载:http://download.csdn.net/detail/wang7dao/4416172

# rpm -ihv expect-5.43.0-8.el5.i386.rpm
# rpm -ihv expect-devel-5.43.0-8.el5.i386.rpm

2、使用脚本文件的例子--实现自动输密码

#!/usr/bin/expect -f
set password 123456
#download
spawn scp root@192.168.1.218:/root/a.wmv /home/yangyz/
set timeout 300
expect "root@192.168.1.218's password:"
set timeout 300
send "$password\r"
set timeout 300
send "exit\r"
expect eof www.2cto.com

3、在sh脚本中嵌入expect的例子--通过连上一个公网的服务器再转跳到一个内网的服务器上,用脚本实现不用输密码,直接使用./goto.sh servername

#!/bin/bash
passmsmallq10="a"
passzhsh="a"
passfcwr="b"
passwapfx="c"
passadfx="d" ip1="200.100.10.10"
ip2="10.100.100.70"
ip3="10.100.100.60"
ip4="10.100.100.10"
ip5="10.100.100.20" case $1 in
"zhsh") passstr=$passzhsh ipstr=$ip2 ;;
"fcwr") passstr=$passfcwr ipstr=$ip3 ;;
"wapfx") passstr=$passwapfx ipstr=$ip4 ;;
"adfx") passstr=$passadfx ipstr=$ip5 ;;
*) echo "The parameter $1 isn't exist"
exit 0 ;; www.2cto.com
esac
command1="ssh -l m_smallq -p 36000 $ip1"
command2="ssh -l mqq -p 36000 $ipstr" expect -c "
set timeout 60;
spawn $command1;
expect {
\"221.130.15.10's password:\" {send \"$passmsmallq10\r\"; exp_continue}
\"m_smallq\" {send \"$command2\r\"; exp_continue}
\"mqq's password:\" {send \"$passstr\r\";interact}
}
"
对上面例子的expect的解说
expect -c "..."  --里面输入命令
expect {...}     --里面的多行记录,从上向下扫描匹配,谁先匹配谁先处理。
  www.2cto.com 

4、ssh到另一台机子执行df -h后退出,要点是send后面可以跟多个命令,通过\r来分行成多个命令

#!/bin/bash
ip1="183.62.178.191"
command1="ssh -l root -p 14322 $ip1" expect -c "
spawn $command1;
expect {
\"183.62.178.191's password:\" {send \"aa\r\"; exp_continue}
\"root@\" {send \"df -h\r exit\r\"; exp_continue}
}
"

自动交互式脚本--expect的更多相关文章

  1. [转帖]自动交互式脚本--expect

    自动交互式脚本--expect https://www.cnblogs.com/zhuiluoyu/p/4873869.html 我们经常会遇到一些需要与服务器程序打交道的场景,比如,从登陆某个服务器 ...

  2. 交互式脚本expect场景示例

    expect语法示例 #spawn 新建一个进程,这个进程的交互由expect控制 #expect 等待接受进程返回的字符串,直到超时时间,根据规则决定下一步操作 #send 发送字符串给expect ...

  3. linux自动交互工具expect,tcl安装和安装包,以及自动互信脚本

    linux自动交互工具expect,tcl安装,以及自动互信脚本 工作中需要对几十台服务器做自动互信,无意中发现expect命令,研究一番. 在网上找了许多资料也没有安装成功,摸索着总算成功了.现分享 ...

  4. centos shell编程4【分发系统】 服务器标准化 mkpasswd 生成密码的工具 expect讲解 expect传递参数 expect自动同步文件 expect指定host和要同步的文件 expect文件分发系统 expect自动发送密钥脚本 Linux脚本执行方式 第三十八节课

    centos shell编程4[分发系统] 服务器标准化  mkpasswd 生成密码的工具  expect讲解   expect传递参数   expect自动同步文件  expect指定host和要 ...

  5. expect 实现自动交互脚本

    1. 说明 在编写脚本时,可能会遇到需要在另一台主机上执行一个命令,或者在本机拷贝另一台主机内的一个文件.如果两台主机之间没有做互信,就会牵扯到用户输入密码的交互过程,这对编写自动脚本来说, 就行不通 ...

  6. linux自动化交互脚本expect详解set timeout 5是 意思是在expect语句中,5s后超时,不再作出选择。

    linux自动化交互脚本expect详解  更新时间:2020年10月21日 10:13:20   作者:lendsomething     这篇文章主要介绍了linux自动化交互脚本expect的相 ...

  7. SQL Server镜像自动生成脚本

    SQL Server镜像自动生成脚本 镜像的搭建非常繁琐,花了一点时间写了这个脚本,方便大家搭建镜像 执行完这个镜像脚本之后,最好在每台机器都绑定一下hosts文件,不然的话,镜像可能会不work 1 ...

  8. 企业IT管理员IE11升级指南【15】—— 代理自动配置脚本

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

  9. mysql 自动备份和nginx自动安装脚本

    一.自动备份Mysql脚本: 如下脚本为mysql自动备份脚本,仅供参考,可以根据实际情况修改. #!/bin/sh #auto backup mysql #wugk #Define PATH定义变量 ...

随机推荐

  1. RFID UHF(EPC)标签使用常识

    文章复制来的,原作者原文点击这里 现在做UHF应用的越来越多了,如何根据实际应用设计系统以达到更佳的使用效果,其中对UHF标签相关内容的了解至关重要,很多朋友对标签的了解不多,在此不才,整理了一些资料 ...

  2. 修改mysql中的auto_increment

    在mysql数据库中,如何修改自增值auto_increment呢?请看下面的语句: 1.sql语句 ALTER TABLE table_name AUTO_INCREMENT=1 2截断表,trun ...

  3. atitit.设计文档---操作日志的实现

    atitit.设计文档---操作日志的实现 日志查询 1 ----mybatis  配置... 1 添加日志 1 日志查询 <a class="l-link" href=&q ...

  4. 源码分析HotSpot GC过程(二):DefNewGeneration的GC过程

    由于虚拟机的分代实现,虚拟机不会考虑各个内存代如何实现垃圾回收,具体的工作(对象内存的分配也是一样)由各内存代根据垃圾回收策略自行实现. DefNewGeneration的使用复制算法进行回收.复制算 ...

  5. firewalld增加端口访问权限

    firewall-cmd --zone=public --add-port=80/tcp --permanent firewall-cmd --reload

  6. Pgsql排序让空值NULL排在数字后边

    遇到一种情况,对数字进行排序的时候,出现NULL在数字后面的情况,现在的需求是NULL排在前面然后才是升序的排数字 [Oracle 结论] order by colum asc 时,null默认被放在 ...

  7. PHP uxf framework 在模版中加入url标签

    1. 确保不修改discuz代码: 2. 继承discuz template类,重载parse_template 方法:由于discuz在模版引擎这一块没有考虑扩展性,对标签的解析全部写在一个方法中, ...

  8. Android 性能测试之TraceView的使用

    Traceview是android平台配备一个很好的性能分析的工具.它可以通过图形化的方式让我们了解我们要跟踪的程序的性能,并且能具体到method. 在SDK路径\tools目录下. 1.在开始使用 ...

  9. [JS] jquery控件基本要点备份

    (1)CDN Google CDN:<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min. ...

  10. 我为什么喜欢Go语言123123

    从2000年至今,也写了11年代码了,期间用过VB.Delphi.C#.C++.Ruby.Python,一直在寻找一门符合自己心意和理念的语言.我很在意写代码时的手感和执行的效率,所以在Go出现之前一 ...