expect主要用來實現自動和交互式任務進行通信,而不需要認為的干預。在Linux下很多的命令都是交互式的,比如密碼修改的命令,無論是:passwd或者yppasswd,都要提示用戶輸入密碼、再確認一次密碼等。
應用的實例(自己碰到的):集群管理的後台網站,root用戶登錄頁面後可以創建新用戶和修改用戶密碼等。這時修改用戶密碼在Linux中就需要交互的實現,而我們從PHP中傳參的時候,可以將$user,$oldpassword,$newpassword傳進去,這個很容易實現,但是滿足不了底層命令執行時的交互形式。此時expect封裝來實現這種交互式的密碼修改就再好不過了。
expect實現交互式密碼修改的實例:
#!/bin/sh
# \
exec expect -f "$0" ${1+"#@"}
set password [lindex $argv 1]
spawn passwd [lindex $argv 0]
sleep 1
expect "assword:"
send "$password\r"
expect "assword:"
send "$password:\r"
expect eof
這裡有幾個特殊的符號相信大家都不陌生:$0 , #@ 等。。。
set password [lindex $argv 1] 這裡是為變量賦值,我們將文件保存為chpasswd.sh時,執行方式為:chpasswd.sh username password 而這裡的[lindex $argv 1] 就是獲得輸入的第二個參數,對應上面就是password 。 這裡我們第一次輸入的密碼和第二次輸入的密碼的檢驗在在前台判斷的是否為空,是否不相等,只有不為空,而且兩次輸入的相同的密碼才會傳入,總之就是其他對密碼條件的限制都是在前台實現的。
spawn passwd [lindex $argv 0] 這裡spawn是啟動一個線程來執行的意思。即啟動線程來執行passwd這個命令,$argv 0 就是我們輸入的第一個參數,username
expect "assword:"是用來匹配字符串的,這點可以參考我們在命令行下輸入passwd時的提示信息:
當匹配到的時候就輸入下面的值,即:send "$password\r" , 這點還是很容易理解的。
當執行完之後,不要忘記了加上expect eof 它會自動檢測是否執行結束。
在這裡,我遇到了一種特殊的情況,當在頁面提交修改用戶密碼後,執行了此命令,但是不知道什麼原因,同時將用戶登錄後的shell目錄也給修改了,即:
cat -n /etc/passwd | grep "$usrname" 之後出現的信息為:username:x:556:173:/wps/home/username:-U
導致切換用戶時無法正常切換:即執行 su - username 時提示:
剛開始的時候我查看: id hou 此時的輸出都可沒改變密碼之前是一樣的,因此確定是這裡的原因,怎麼辦呢?expect自動該回來就好了,於是在上面的代碼中添加:
此時在網頁中重新提交修改密碼的指令,就可以正常執行了。