Expect是由 Don Libes 基於Tcl語言開發的,並被普遍應用於交互式操做和自動化測試的場景中,它尤爲適用於須要對多臺服務器執行相同操做的環境中,能夠大幅度提升系統管理人員的工做效率。目前,大部分 Unix/Linux 系統安裝有expect。萬一系統中沒有,能夠從 http://expect.nist.gov/| f52496c84460745c17c9a9c5df59acb61 | 下載相應的包安裝。linux
Expect做爲基於Tcl的高級語言,增長了一些特殊的語法。傳統意義上的Expect是以Tcl擴展包的形式出現的,任何Tcl語言編寫的應用程序均可以加載Expect功能;此外,Expect已經以模塊的方式移植到了Perl和Python語言中,所以用戶一樣能夠在Perl和Python腳本中利用Expect強大的交互功能。正則表達式
send 、 expect 和 spawn 是Expect語言最基本的命令。
send命令會發送字符牀給指定進程(process)。
expect命令會等待接受該進程返回的結果而且會根據返回的字符串來決定下一步的操做。
spawn命令能夠發起一個進程的運行。
進入expect環境後才能夠執行的expect內部命令bash
$ expect expect1.1> send .... expect1.1> expect .... ........
send命令接收一個字符串做爲參數併發送給指定的進程從send "hello world"
這行代碼中,send會送出字符串 hello world
。若是expec早已經開始與某一個程序進行交互,那麼這個字符串將被髮送給該程序;而在一般狀況下,這個字符串會被送到標準輸出設備。服務器
expect命令則等待一個響應,一般是來自於expect正在與之交互的進程,或者來自於標準輸入設備;它會等待一個指定的字符串或者知足給定的正則表達式的任何字符串。咱們能夠建立一個名爲response.expect
的文件,來看expect是如何處理的,其內容以下:併發
#!expect -f expect "hi" send "hello there"
終端中運行 $ expect response.expect
,它會等待來自標準輸入設備的響應,知道用戶輸入hi
並回車,它纔會發送 hello there
到標準輸出設備,並回車。而後結束expect腳本的運行。可是若是用戶沒有輸入hi
並回車,那麼expect會繼續等待hi
;輸入其餘的字符並不會影響到expect的工做。一般狀況下,expect會一直等待輸入,直到最終超時退出。此外,expect還支持使用正則表達式來預防expect匹配到未預想到的輸入數據。ssh
spawn命令會調用另外一個程序。它的第一個參數要啓動程序的名字;剩餘的參數則會被傳遞給該程序做爲參數。好比:測試
expect1.1> spawn ssh username@192.168.1.1
命令會衍生出一個ssh進程,以username用戶的身份登錄ip地址爲192.168.1.1的電腦中。spa
用戶經過spawn,send和expect這三個基本命令,就能夠編寫一段expect程序來實現自動化工做。code
$ sudo emerge -avt dev-tcltk/expect
當你想經過lftp登錄別人的電腦同步文件時,若只執行lftp sftp:://user@x.x.x.x
登錄了別人的電腦,你會發現其實這只是一種假象,實際上你並無成功登錄別人的電腦,因此你需先執行ssh user@x.x.x.x
而後在執行上述命令,便可登錄成功。這樣作的話,你須要屢次輸入ip、用戶名、密碼,很費時間。爲了可以提升效率,能夠藉助expect腳本。過程以下:建立一個ssh.expect的腳本,分別說一下執行腳本時有參數的腳本內容和無參數的腳本內容。進程
有參數的腳本內容以下:
#!/usr/bin/expect set timeout 1 set host [lindex $argv 0] set user [lindex $argv 1] set password [lindex $argv 2] spawn ssh $host -l $user expect { "(yes/no)?" { send "yes" expect "Password" send "$password\r" } "Password:" { send "$password\r" } } send "exit \n" spawn lftp sftp://$user@$host expect "Password:" send "$password\r" interact
假如你想以xiaomi
的用戶名登錄ip
爲192.168.0.50
登錄密碼爲123
的電腦,則在終端執行$ expect ssh.expect 192.168.0.50 xiaomi 123
,終端顯示lftp xiaomi@192.168.0.50:~>
。
無參數的腳本內容以下:
#!/usr/bin/expect set timeout 1 set host 192.168.0.50 set user xiaomi set password 123 spawn ssh $host -l $user expect { "(yes/no)?" { send "yes" expect "Password" send "$password" } "Password:" { send "$password\r" } } send "exit \n" spawn lftp sftp://$user@$host expect "Password:" send "$password\r" interact
在終端執行$ expect ssh.expect
,終端顯示lftp xiaomi@192.168.0.50:~>
。
其中timeout
爲send將信息發送給標準輸入設備等待執行的時間,你能夠修改一下變量值,觀察如下效果。
注意send 「123\r」
中的123
爲你的sudo密碼。
#!/usr/bin/expect set timeout 60 set kernel [lindex $argv 0] spawn su expect "Password:" send "123\r" expect "#" send "cd /usr/src/ \n" expect "#" send "cp ./linux/.config ./linux-$kernel-gentoo/ \n" expect "#" send "rm linux \n" expect "#" send "ln -s /usr/src/linux-$kernel-gentoo linux \n" expect "#" send "cd linux \n" expect "#" send "make -j4 && make modules_install \n" expect "#" send "mount /boot && rm /boot/kernel-* \n" expect "#" send "cp arch/x86/boot/bzImage /boot/kernel-$kernel-gentoo \n" expect "#" send "grub2-mkconfig -o /boot/grub/grub.cfg \n" expect "#" send "grub2-install /dev/sda \n" expect "#" send "exit \n" interact
$ expect kernel_renew.expect 4.2.1//4.2.1爲你內核新版本號