EXPECT 用法
expect是基於TCL的相對簡單的一個免費腳本編程工具語言,用來實現自動和交互式任務進行通信,無需人的
手工干預,比如ssh\FTP等,這些程序正常情況都需要手工與它們進行交互,而使用EXPECT就可以模擬人手工交互的過程,實現自動的
和遠程的程序交互,從而達到自動化的目的。
EXPECT是一個用來實現自動交互功能的軟件套件(EXPECT is a software suite for automating interactive tools)
雖然,使用C、perl等一樣可以實現這樣的功能,而expect做的更加專業出色、簡單、而且除支持unix/linux平臺外,它還支持
windows平臺,它就是爲系統管理和軟件測試方面的自動交互類需求而產生的。
2.expect程序工作流程
expect的工作流程可以理解爲,spawn啓動進程-->expect期待關鍵字---->send向進進程發送字符--->退出結束。
3.安裝EXPECT軟件
[root@clientC ~]# yum install expect -y Loaded plugins: fastestmirror, refresh-packagekit Determining fastest mirrors * base: mirror.bit.edu.cn * extras: ftp.sjtu.edu.cn * updates: mirrors.hust.edu.cn base | 3.7 kB 00:00 base/primary_db | 4.6 MB 00:00 [root@clientC ~]# rpm -qa | grep expect expect-5.44.1.15-5.el6_4.x86_64 [root@clientC ~]# mkdir /scirts [root@clientC ~]# cd /scirts/ [root@clientC scirts]# vi xp-excpec.exp [root@clientC scirts]# chmod 700 xp-excpec.exp [root@clientC scirts]# cat xp-excpec.exp #!/usr/bin/expect spawn ssh -p22 [email protected] /sbin/ifconfig eth0 set timeout 60 expect "*password:" send "ww123123\n" expect eof exit [root@clientC scirts]# ./xp-excpec.exp spawn ssh -p22 [email protected] /sbin/ifconfig eth0 [email protected]'s password: eth0 Link encap:Ethernet HWaddr 00:0C:29:D8:5D:8C inet addr:192.168.20.5 Bcast:192.168.20.255 Mask:255.255.255.0 inet6 addr: fe80::20c:29ff:fed8:5d8c/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:9392 errors:0 dropped:0 overruns:0 frame:0 TX packets:2518 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:952097 (929.7 KiB) TX bytes:461897 (451.0 KiB)
【EXPECT語法】
Expect中的 命令是最重要的部分了,命令的使用語法如下;
命令{選項} 參數
a.1.【spawn】
spawn命令是expect的初始命令,它用於啓動一個進程,之後所有expect操作都在這個進程中進行,如果
沒有spawn語句,整個expect就無法執行了,spawn使用方法如下;
spawn ssh [email protected]
在spawn命令後面,直接加上要啓動的進程、命令等信息,除此之外,spawn還支持其他選項如;
-open 啓動文件進程,具體說明省略。
-ignore 忽略某些信號,具體說明省略。
a.2 【expect 使用方法:】
expect 表達式 動作 表達式 動作。。。。。。。
expect 命令用於等候一個相匹配內容的輸出,一旦匹配上就執行expect後面的動作或命令,這個命令接受幾個
特有參數,用的最多的就是-re,表示使用正則表達式的方式匹配,使用起來就像這樣;
spawn ssh [email protected] expect "password:"{send "ww123123\r"}
從上面的例子可以看出。expect是依附與spawn命令的,當執行ssh命令後,expect就匹配命令執行後的關鍵字:password:,
如果匹配到關鍵字就會執行後面包含在{}括號中的exp_send動作,匹配以及動作可以放在二行,這樣就不需要使用{}括號了,
就像下面這樣,實際完成的功能與上面是一樣的;
spawn ssh [email protected] expect "password:" send "xiaoping\r"
expect 命令還有一種用法,它可以在一個expect匹配中多次匹配關鍵字,並給出處理動作,只需要將關鍵字放在一個大括號
就可以了,當然還有exp_continue.
spawn ssh [email protected] expect { "yes/no"{exp_send "yes\r";exp_continue} "*password:" {exp_send "123123\r"} }
a.3【exp_send和send】
在上面的介紹中,我們已經看到exp_send命令的使用,exp_send命令是expect中的動作命令,它還有一個完成同樣工作的
同胞:send,exp_send命令可以發送一些特殊符號,我們看到了\r(回車),還有一些其他的比如:\n(換行)、\t(製表符)等等
這些都是與TCL中的特殊符號相同。
spawn ssh [email protected] expect { "yes/no" {send "yes\r";exp_continue} "*password:" {exp_send "123456\r"} }
send命令有幾個可用的參數;
-i 指定spawn_id,這個參數用來向不同spawn_id的進程發送命令,是進行多程序控制的關鍵參數。
-s s代表slowly,也就是控制發送的速度,這個參數使用的時候要與expect中的變量send_slow相關聯。
a.4【exp_continue】
這個命令一般用在動作中,它被使用的條件比較苛刻,看看下面的例子;
#!/usr/bin/expect spawn ssh -p22 [email protected] /sbin/ifconfig eth0 set timeout 60 expect { -timeout 1 "yes/no" { exp_send "yes\r";exp_continue } "*password:" {exp_send "123456\r"} timeout {puts "expect was timeout by xiaoping.";return} } expect eof exit
在這個例子中,可以發現exp_continue命令的使用方法,首先它要處於一個expect命令中,然後它屬於一種動作命令
完成的工作就是從頭開始偏歷,也就是說如果沒有這個命令,匹配第一個關鍵字以後就會繼續匹配第二關鍵字,但有了這個
命令後,匹配第一個關鍵字以後,第二次匹配依然從第一個關鍵字開始。
A.5【send_user】
send_user 命令用來把後面的參數輸出到標準輸出中去,默人的send、exp_send 命令都是將參數輸出到程序中去的,
用起來就像這樣;
send_user "please input passwd:" 這個語句就可以在標準輸出中打印please input passwd:字符了。 [root@~]vi xp_3.exp #!/usr/bin/expect if { $argc != 3 } { send_user "usage:expect scp-expect.exp file host dir\n" exit } #define var set file [lindex $argv 0] set host [lindex $argv 1] set dir [lindex $argv 2] set password "123123" #spawn scp /etc/hosts [email protected]:/etc/hosts spawn scp -p22 $file root@$host:$dir expect { "yes/no" {send "yes\r";exp_continue} "*password" {send "$password\r"} timeout {puts "expect connect timeout,pls contact xp";return} } expect eof exit -onexit { send_user "xiaoping say good bye to you!\n" } #expect xiaoping.exp
【Expect 變量】
expect中有很多有用的變量,它們的使用方法與TCL語言中的變量相同,比如:
set 變量名 變量值 #設置變量的方法
puts $變量名 #讀取變量的方法
#define var set file [lindex $argv 0] set host [lindex $argv 1] set dir [lindex $argv 2] set password "123123123"
【Expect 關鍵字】
expect中的特殊關鍵字用於匹配過程,代表某些特殊含義或狀態,一般用於expect族命令中而不能在外面單獨使用,
也可以理解爲事件,使用上類似於:
expect eof { }
7.1 eof
eof (end-of-file)關鍵字用於匹配結束符,比如文件的結束符,TFP傳輸停止等情況,在這個關鍵字後跟上動作來做
進一步的控制,特別是FTP交互操作方面,它的作用很大,用一個例子看看:
spawn FTP [email protected] expect { "password:" {exp_send "who am I"} eof {ftp connet close} } interact {}
7.2 【timeout】
timeout 是expect中的一個重要變量,它是一個全局的時間控制開關,你可以通過爲這個變量賦值來規定整個expectc操作的
時間,注意這個變量是服務與expect全局的,它不會糾纏某一條命令,即使命令沒有任何錯誤,到時間依然會激活這個變量,但
這個時間到達以後除了激活一個開關之外不會做其他的事情,如何處理腳本編寫人員的事情,看看它的實際使用方法:
set timeout 60 spawn ssh [email protected] expect "password:" {send "word\r"} expect timeout {puts "Expect was timeout";return}
上面的處理中。首先將timeout變量設置爲60秒,當出現問題的時候程序可能會停止下來,只要到60秒,就會激活下面的timeout
動作,這裏我打印一個信息並且停止了腳本的運行,你可以做更多的其他事情,看自己的意思。
在另外一種expect格式中我們還有一種設置timeout變量的方法,看看下面的例子;
spawn ssh [email protected] expect { -timeout 60 -re "password:" {exp_send "word\r"} -re "Topsecos#" { } timeout {puts "Expect was timeout";return} }
在expect命令中間加上一個小橫杆,也可以設置timeout變量
timeout 變量中,設置爲0表示立即超時,-1則表示永久不超時。
expect { -timeout 20 "yes/no" {send "yes\r";exo_continue} "*password" {send "$password\r"} timeout {puts "expect connet timeout ,pls contact xp";return} }
expect的命令行參數參考了c語言的,與bash shell有點不一樣。其中,$argc爲命令行參數的個數,$argv0爲腳本名字本身,$argv爲命令行參數。
[lrange $argv 0 0]表示第1個參數,[lrange $argv 0 4]爲第一個到第五個參數。與c語言不一樣的地方在於,$argv不包含腳本名字本身。
【實戰1】批量分發文件
[root@clientC scirts]# cat fenfa_hosts.sh #!/bin/sh . /etc/init.d/functions #調用fuctions函數 for ip in `cat iplist` do expect xp-scp.exp /etc/hosts $ip /xp >/dev/null 2>&1 #可以修改別的拷貝文件 if [ $? = 0 ];then action "$ip" /bin/true else action "$ip" /bin/false fi done [root@clientC scirts]# cat xp-scp.exp #!/urs/bin/expect -f if { $argc != 3 } { send_user "usage: expect xp-scp.exp file host dir\n" exit } #define var set file [lindex $argv 0] set host [lindex $argv 1] set dir [lindex $argv 2] set password "ww123123" spawn scp -P22 -p $file roor@$host:$dir set timeout 10 expect { -timeout 2 "yes/no" {send "yes\r" ;exp_continue} "*password:" {send "$password\r"} timeout {puts "expect connect timeout,pls contact xp"; retur} } expect eof exit [root@clientC scirts]#
【實戰2】:使用expect實戰批量分發ssh密鑰文件
[root@clientC ~]# ssh-keygen -t dsa Generating public/private dsa key pair. Enter file in which to save the key (/root/.ssh/id_dsa): Created directory '/root/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/id_dsa. Your public key has been saved in /root/.ssh/id_dsa.pub. The key fingerprint is: 2a:e1:3a:1a:b1:ec:eb:95:e5:16:d7:bb:7a:e2:88:87 root@clientC The key's randomart image is: +--[ DSA 1024]----+ | | | | | | | . | |. .o .S. | |.o .+.o. . | |o. o+o. . | |..oEoo.. .. | |o=oo...o+. | +-----------------+ [root@clientC ~]# cd .ssh/ [root@clientC .ssh]# ls -a . .. id_dsa id_dsa.pub [root@clientC .ssh]# grep \.ssh /etc/ss ssh/ ssl/ [root@clientC .ssh]# grep \.ssh /etc/ssh/ssh ssh_config ssh_host_dsa_key ssh_host_key ssh_host_rsa_key sshd_config ssh_host_dsa_key.pub ssh_host_key.pub ssh_host_rsa_key.pub [root@clientC .ssh]# grep \.ssh /etc/ssh/sshd_config # $OpenBSD: sshd_config,v 1.80 2008/07/02 02:24:18 djm Exp $ # This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. # This sshd was compiled with PATH=/usr/local/bin:/bin:/usr/bin # The strategy used for options in the default sshd_config shipped with [root@clientC .ssh]# cp id_dsa.pub id_dsa.pub.back [root@clientC .ssh]# mv id_dsa.pub .ssh/authorized_keys mv: cannot move `id_dsa.pub' to `.ssh/authorized_keys': No such file or directory [root@clientC .ssh]# ^C [root@clientC .ssh]# mv id_dsa.pub authorized_keys [root@clientC .ssh]# ls -a . .. authorized_keys id_dsa id_dsa.pub.back [root@clientC .ssh]# mv id_dsa id_dsa id_dsa.pub.back [root@clientC .ssh]# mv id_dsa /xp/ [root@clientC .ssh]# ls -a . .. authorized_keys id_dsa.pub.back [root@clientC .ssh]# cd .. [root@clientC ~]# scp -P22 -p .ssh/ [email protected]:~/ The authenticity of host '192.168.20.5 (192.168.20.5)' can't be established. RSA key fingerprint is c1:28:b4:c3:f6:3d:85:bf:b2:df:59:17:d5:9f:65:2e. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.20.5' (RSA) to the list of known hosts. [email protected]'s password: .ssh: not a regular file [root@clientC ~]# scp -P22 -p .ssh/ [email protected]:~/ [email protected]'s password: .ssh: not a regular file [root@clientC ~]# scp -P22 -p -r .ssh/ [email protected]:~/ [email protected]'s password: id_dsa.pub.back 100% 602 0.6KB/s 00:00 authorized_keys 100% 602 0.6KB/s 00:00 known_hosts 100% 394 0.4KB/s 00:00 [root@clientC ~]# ^C #HostKey /etc/ssh/ssh_host_key #HostKey /etc/ssh/ssh_host_rsa_key #HostKey /etc/ssh/ssh_host_dsa_key #AuthorizedKeysFile .ssh/authorized_keys # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts # Change to yes if you don't trust ~/.ssh/known_hosts for #PidFile /var/run/sshd.pid Subsystem sftp /usr/libexec/openssh/sftp-server [root@clientC .ssh]# grep \AuthorizedKeysFile /etc/ssh/sshd_config #AuthorizedKeysFile .ssh/authorized_keys [root@clientC ~]# mkdri /server/scripts -p [root@clientC scripts]# cat fenfa_sshkey.sh #!/bin/sh . /etc/init.d/functions for ip in `cat iplist` do expect ex-ssh.exp ~/.ssh/ $ip ~/.ssh/ >/dev/null 2>&1 if [ $? = 0 ];then action "$ip" /bin/true else action "$ip" /bin/false fi done [root@clientC scripts]# 特別提示:如果是禁止了root遠程連接,那麼就使用普通用戶加sudo的方式在結合expect大量分發。 expect可以大量分發查詢機器狀態 【實戰3】 [root@clientC scripts]# cat ex-free.exp #!/urs/bin/expect if { $argc != 3 } { send_user "usage: expect xp-scp.exp file host dir\n" exit } #define var set file [lindex $argv 0] set host [lindex $argv 1] set dir [lindex $argv 2] set password "123456" #spawn scp -P22 -p -r $file roor@$host:$dir spawn ssh -P22 root@$file $host $dir set timeout 10 expect { -timeout 10 "yes/no" {send "yes\r" ;exp_continue} "*password:" {send "$password\r"} timeout {puts "expect connect timeout,pls contact xp";return} } expect eof exit [root@clientC scripts]# cat piliang.sh #!/bin/bash for ip in `cat iplist` do expect ex-free.exp $ip free -m done [root@clientC scripts]# cat iplist 192.168.20.5 192.168.20.10
【測試】
[root@clientC scripts]# sh piliang.sh spawn ssh -P22 [email protected] free -m [email protected]'s password: total used free shared buffers cached Mem: 199 184 15 0 57 18 -/+ buffers/cache: 107 92 Swap: 1055 0 1055 spawn ssh -P22 [email protected] free -m ssh: connect to host 192.168.20.10 port 22: No route to host expect: spawn id exp4 not open while executing "expect eof" (file "ex-free.exp" line 20) [root@clientC scripts]#
~