一、expect简介
expect是基于TCL的相对简单的一种免费的脚本编程工具语言,用来实现自动和交互式任务程序进行通信,无需人的手工干预,如:SSH、FTP等。这些程序正常情况下都需要手工进行交互,而使用expect就可以模拟人手工交互的过程,实现自动和远端程序的交互,从来达到自动化运维的目的。
官方解释:expect是一个用来实现自动交互功能的软件套件(expect is a software suite for automating interactive tools)
expect支持Unix、linux、windows平台。
二、expect安装
安装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、使用yum安装
#yum install expect -y
三、expect语法
expect程序工作流程:
sqawn启动进程==》expect期待关键字==》send向进程发送字符==》退出结束。
spawn:是expect的初始命令,它用于启动一个进程,之后所有expect操作都在这个进程中进行,如果没有spawn语句,整个expect就无法执行,如:spawn ssh [email protected] 在spawn命令后面,直接加上要启动的进程,命令等信息
spawn支持的选项有:-open 启动文件进程,-ignore 忽略某些信号。
expect:使用方法:expect 表达式 动作 表达式 动作 .....
expect命令用于等候一个匹配内容的输出,一旦匹配上就执行expect后面的动作或命令,这个命令接受几个特有参数,用的最多的是-re,表示使用正则表达式的方式来匹配,如:
spawn ssh [email protected]
expect "password:" {send "123456\r"}
从例子看出,expect是依附于spawn命令的,当执行ssh命令后,expect就匹配命令执行后的关键字:"password:",如果匹配到关键字就会执行后面包含在{}括号中的send或exp_send动作,匹配及动作可以放在二行,如不需要使用{}括号可以写成多行:
expect "password:"
send "123456\r"
expect命令还有一种用法,它可以在一个expect匹配中多次匹配关键字,并给出处理动作,只需要将关键字放在一个大括号中就可以了,当然还要有exp_continue:
expect {
"yes/no" { exp_send "yes\r";exp_continue }
"*password:" { exp_send "123456\r" }
}
exp_send 和send:
使用基本相同,是expect中的动作命令。它可以发送一些特殊符号如:\r(回车),\n(换行),\t(制表符),等,这些都与TCL中的特殊符号相同。
exp_continue:命令它要处于expect命令中,然后它属于一个动作命令,完成的工作就是从头开始遍历,也就是说如果没有这个命令,匹配第一个关键字以后就会继续匹配第二个关键字,但有个这个命令后,匹配第一个关键字以后,第二次匹配仍然从第一个关键字开始。
send_user:用来把后面的参数输出到标准输出中去,如:
send_user "please input password:"
这个语句就可以在标准输出中打印please input password:字符了。
exit:直接退出脚本,也可以在退出前输出一些信息,如:
exit -onexit {
send_user "say you baby!\n"
expect变量:
set: 变量名 变量值 #用来设置变量的方法
如:set file [lindex $argv 0] #接收参数变量1
set host [lindex $argv 1] #接收参数变量2
set password "123456"
puts $变量名 #读取变量的方法
expect关键字:
eof:用于匹配结束符
timeout:它是expect中的一个重要变量,它是一个全局性的时间控制开关。
如:set timeout 200
-timeout 200
四、expect使用案列
列1:ftp拷贝文件自动输入密码拷贝
<code>#!/usr/bin/expect #声明程序执行命令</code>
<code>set</code> <code>password 123456 </code><code>#设置密码</code>
<code>#download</code>
<code>spawn </code><code>scp</code> <code>[email protected]:</code><code>/root/a</code><code>.wmv </code><code>/home/yangyz/</code> <code>#生成进程链接远程服务器</code>
<code>set</code> <code>timeout 300 </code><code>#设置超时时间</code>
<code>expect </code><code>"[email protected]'s password:"</code> <code>#匹配内容输出</code>
<code>set</code> <code>timeout 300 </code>
<code>send </code><code>"$password\r"</code> <code>#发送密码给进程</code>
<code>send </code><code>"exit\r"</code> <code>#发送退出命令</code>
<code>expect eof</code>
列2:自动ssh登陆
<code>#!/usr/bin/expect</code>
<code>spawn </code><code>ssh</code> <code>-p22 [email protected] </code><code>/sbin/ifconfig</code> <code>eth0</code>
<code>set</code> <code>timeout 30</code>
<code>expect {</code>
<code>-timeout 1</code>
<code>"yes/no"</code> <code>{ exp_send </code><code>"yes\r"</code><code>;exp_continue }</code>
<code>"*password:"</code> <code>{ exp_send </code><code>"123456\r"</code> <code>}</code>
<code>timeout { puts </code><code>"expect was timeout by hehe."</code><code>;</code><code>return</code> <code>}</code>
<code>}</code>
<code>exit</code>
列3:ssh免密钥分发
<code>[root@mail .</code><code>ssh</code><code>]</code><code># ssh-keygen -t rsa</code>
<code>Generating public</code><code>/private</code> <code>rsa key pair.</code>
<code>Enter </code><code>file</code> <code>in</code> <code>which</code> <code>to save the key (</code><code>/root/</code><code>.</code><code>ssh</code><code>/id_rsa</code><code>): </code>
<code>Enter passphrase (empty </code><code>for</code> <code>no passphrase): </code>
<code>Enter same passphrase again: </code>
<code>Your identification has been saved </code><code>in</code> <code>/root/</code><code>.</code><code>ssh</code><code>/id_rsa</code><code>.</code>
<code>Your public key has been saved </code><code>in</code> <code>/root/</code><code>.</code><code>ssh</code><code>/id_rsa</code><code>.pub.</code>
<code>The key fingerprint is:</code>
<code>80:a0:99:3a:46:32:ee:fb:d2:48:25:37:cc:a5:83:36 [email protected]</code>
<code>The key</code><code>'s randomart image is:'</code>
<code>+--[ RSA 2048]----+</code>
<code>| . |</code>
<code>| + . o |</code>
<code>|*.+ + . |</code>
<code>|=E O . |</code>
<code>|+o= o S |</code>
<code>|oo |</code>
<code>|..o |</code>
<code>| o.. |</code>
<code>| .o. |</code>
<code>+-----------------+</code>
<code>[root@mail .</code><code>ssh</code><code>]</code><code># pwd</code>
<code>/root/</code><code>.</code><code>ssh</code>
<code>[root@mail .</code><code>ssh</code><code>]</code><code># ls</code>
<code>id_rsa id_rsa.pub known_hosts</code>
<code>[root@mail .</code><code>ssh</code><code>]</code><code># cp id_rsa.pub id_rsa.pub.bak</code>
<code>[root@mail .</code><code>ssh</code><code>]</code><code># mv id_rsa.pub authorized_keys</code>
<code>[root@mail .</code><code>ssh</code><code>]</code><code># mv id_rsa /server/</code>
<code>[root@mail .</code><code>ssh</code><code>]</code><code># cd /server/scripts/</code>
<code>[root@mail scripts]</code><code># cat sshkey.exp </code>
<code>#ssh key fenfa</code>
<code>set</code> <code>password </code><code>"123.com"</code>
<code>set</code> <code>s_file [lindex $argv 0]</code>
<code>set</code> <code>d_host [lindex $argv 1]</code>
<code>set</code> <code>d_dir [lindex $argv 2]</code>
<code>set</code> <code>timeout 10</code>
<code>spawn </code><code>scp</code> <code>-P 22 -r -p $s_file root@$d_host:$d_dir</code>
<code>-timeout 5</code>
<code>"yes/no"</code> <code>{send </code><code>"yes\r"</code><code>;exp_continue}</code>
<code>"*password:"</code> <code>{send </code><code>"$password\r"</code><code>}</code>
<code>timeout {puts </code><code>"connect to timeout"</code><code>;</code><code>return</code><code>}</code>
<code>exit</code> <code>-onexit {</code>
<code>send_user </code><code>"exit bye! \n"</code>
<code>[root@mail scripts]</code><code># cat sshkey_fenfa.sh </code>
<code>#!/bin/bash</code>
<code>#fenfa scripts</code>
<code>. </code><code>/etc/init</code><code>.d</code><code>/functions</code>
<code>for</code> <code>i </code><code>in</code> <code>`</code><code>cat</code> <code>/server/scripts/listip</code><code>`</code>
<code>do</code>
<code>expect sshkey.exp </code><code>/root/</code><code>.</code><code>ssh</code> <code>$i </code><code>/root</code> <code>&></code><code>/dev/null</code>
<code>if</code> <code>[ $? -</code><code>eq</code> <code>0 ];</code><code>then</code>
<code>action </code><code>"$i"</code> <code>/bin/true</code>
<code>else</code>
<code>action </code><code>"$i"</code> <code>/bin/false</code>
<code>fi</code>
<code>done</code>
<code>[root@mail scripts]</code><code># cat listip </code>
<code>10.0.0.10</code>
<code>...</code>
<code>10.0.0.112</code>
<code>[root@mail scripts]</code><code># ssh 10.0.0.10</code>
<code>Last login: Tue Aug 1 15:57:20 2017 from 10.0.0.100</code>
<code>[root@zabbix ~]</code><code># ifconfig eth0</code>
<code>eth0 Link encap:Ethernet HWaddr 00:0C:29:DB:44:29 </code>
<code> </code><code>inet addr:10.0.0.10 Bcast:10.0.0.255 Mask:255.255.255.0</code>
<code> </code><code>inet6 addr: fe80::20c:29ff:fedb:4429</code><code>/64</code> <code>Scope:Link</code>
<code> </code><code>UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1</code>
<code> </code><code>RX packets:15111544 errors:0 dropped:0 overruns:0 frame:0</code>
<code> </code><code>TX packets:15940400 errors:0 dropped:0 overruns:0 carrier:0</code>
<code> </code><code>collisions:0 txqueuelen:1000 </code>
<code> </code><code>RX bytes:2595895595 (2.4 GiB) TX bytes:2891681366 (2.6 GiB)</code>
<code>[root@zabbix ~]</code><code># ll ~/.ssh</code>
<code>总用量 12</code>
<code>-rw-r--r-- 1 root root 398 8月 1 14:57 authorized_keys</code>
<code>-rw-r--r-- 1 root root 398 8月 1 15:01 id_rsa.pub.bak</code>
<code>-rw-r--r-- 1 root root 391 8月 1 15:55 known_hosts</code>
列4:cisco交换机自动应用访问控制列表
<code>#telnet </code>
<code>set user </code><code>"pjycm"</code>
<code>set password </code><code>"[email protected]"</code>
<code>set command </code><code>"ip access-group 1 in"</code>
<code>set timeout 10</code>
<code>spawn telnet 10.0.0.1</code>
<code> </code><code>"Username:"</code> <code>{send </code><code>"$user\r"</code><code>;exp_continue}</code>
<code> </code><code>"Password:"</code> <code>{send </code><code>"$password\r"</code><code>;exp_continue}</code>
<code> </code><code>"CM>"</code> <code>{send </code><code>"en\r"</code><code>;exp_continue}</code>
<code> </code><code>"Password:"</code> <code>{send </code><code>"[email protected]\r"</code><code>;exp_continue}</code>
<code> </code><code>"CM#"</code> <code>{send </code><code>"conf t\r"</code><code>;exp_continue}</code>
<code> </code><code>"CM(config)#"</code> <code>{send </code><code>"int vlan 10\r"</code><code>;exp_continue}</code>
<code> </code><code>"CM(config-if)#"</code> <code>{send </code><code>"$command\r"</code><code>}</code>
脚本写的比较简单,如在工作中应用,应加入流程控制判断语句!
本文转自 80后小菜鸟 51CTO博客,原文链接:http://blog.51cto.com/zhangxinqi/1952741