久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

expect如何處理htpasswd交互

201次閱讀
沒有評論

共計 13660 個字符,預計需要花費 35 分鐘才能閱讀完成。

丸趣 TV 小編給大家分享一下 expect 如何處理 htpasswd 交互,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

vim expect_test.sh

#!/usr/bin/expect

set htpasswdpath [lindex $argv 0]

set username [lindex $argv 1]

set userpass [lindex $argv 2]

# spawn the htpasswd command process

spawn htpasswd -c $htpasswdpath $username

# Automate the New password Procedure

expect New password:

send $userpass\r

expect Re-type new password:

send $userpass\r

expect eof

chmod +x expect_test.sh

./expect_test.sh /usr/local/nagios/etc/htpasswd.users(這個是 $argv 0) nagiosadmin(這個是 $argv 1) 123.com(這個是 $argv 2)

Expect 教程中文版
來源: ChinaUnix 博客 日期:2007.02.14 10:58 (共有條評論) 我要評論
Expect 教程中文版
創建時間:2001-04-29
文章屬性:轉載
文章來源:中國科大 BBS 站
[版權聲明]

Copyright(c) 1999

本教程由 * 葫蘆娃 * 翻譯,并做了適當的修改,可以自由的用于非商業目的。
但 Redistribution 時必須拷貝本[版權聲明]。
[BUG]
有不少部分,翻譯的時候不能作到“信,達”。當然了,任何時候都沒有做到“雅”,希望各位諒解。
[原著]

Don Libes: National Institute of Standards and Technology

libes@cme.nist.gov
[目錄]

1. 摘要
2. 關鍵字
3. 簡介
4.Expect 綜述
5.callback
6.passwd 和一致性檢查
7.rogue 和偽終端
8.ftp
9.fsck
10. 多進程控制:作業控制
11. 交互式使用 Expect
12. 交互式 Expect 編程
13. 非交互式程序的控制
14.Expect 的速度
15. 安全方面的考慮
16.Expect 資源
17. 參考書籍
1.[摘要]
現代的 Shell 對程序提供了最小限度的控制(開始,停止,等等),而把交互的特性留給了用戶。這意味著有些程序,你不能非交互的運行,比如說 passwd。有一些程序可以非交互的運行,但在很大程度上喪失了靈活性,比如說 fsck。這表明 Unix 的工具構造邏輯開始出現問題。Expect 恰恰填補了其中的一些裂痕,解決了在 Unix 環境中長期存在著的一些問題。
Expect 使用 Tcl 作為語言核心。不僅如此,不管程序是交互和還是非交互的,Expect 都能運用。這是一個小語言和 Unix 的其他工具配合起來產生強大功能的經典例子。

本部分教程并不是有關 Expect 的實現,而是關于 Expect 語言本身的使用,這主要也是通過不同的腳本描述例子來體現。其中的幾個例子還例證了 Expect 的幾個新特征。

2.[關鍵字]

Expect, 交互,POSIX, 程序化的對話,Shell,Tcl,Unix;
3.[簡介]

一個叫做 fsck 的 Unix 文件系統檢查程序,可以從 Shell 里面用 - y 或者 - n 選項來執行。在手冊 [1] 里面,- y 選項的定義是象這樣的。
“對于 fsck 的所有問題都假定一個“yes”響應;在這樣使用的時候,必須特別的小心,因為它實際上允許程序無條件的繼續運行,即使是遇到了一些非常嚴重的錯誤”

相比之下,- n 選項就安全的多,但它實際上幾乎一點用都沒有。這種接口非常的糟糕,但是卻有許多的程序都是這種風格。文件傳輸程序 ftp 有一個選項可以禁止交互式的提問,以便能從一個腳本里面運行。但一旦發生了錯誤,它沒有提供的處理措施。
Expect 是一個控制交互式程序的工具。他解決了 fsck 的問題,用非交互的方式實現了所有交互式的功能。Expect 不是特別為 fsck 設計的,它也能進行類似 ftp 的出錯處理。
fsck 和 ftp 的問題向我們展示了象 sh,csh 和別的一些 shell 提供的用戶接口的局限性。Shell 沒有提供從一個程序讀和象一個程序寫的功能。這意味著 shell 可以運行 fsck 但只能以犧牲一部分 fsck 的靈活性做代價。有一些程序根本就不能被執行。比如說,如果沒有一個用戶接×××互式的提供輸入,就沒法運行下去。其他還有象 Telnet,crypt,su,rlogin 等程序無法在 shell 腳本里面自動執行。還有很多其他的應用程序在設計是也是要求用戶輸入的。
Expect 被設計成專門針和交互式程序的交互。一個 Expect 程序員可以寫一個腳本來描述程序和用戶的對話。接著 Expect 程序可以非交互的運行“交互式”的程序。寫交互式程序的腳本和寫非交互式程序的腳本一樣簡單。Expect 還可以用于對對話的一部分進行自動化,因為程序的控制可以在鍵盤和腳本之間進行切換。

bes[2]里面有詳細的描述。簡單的說,腳本是用一種解釋性語言寫的。(也有 C 和 C ++ 的 Expect 庫可供使用,但這超出了本文的范圍).Expect 提供了創建交互式進程和讀寫它們的輸入和輸出的命令。Expect 是由于它的一個同名的命令而命名的。
Expect 語言是基于 Tcl 的。Tcl 實際上是一個子程序庫,這些子程序庫可以嵌入到程序里從而提供語言服務。最終的語言有點象一個典型的 Shell 語言。里面有給變量賦值的 set 命令,控制程序執行的 if,for,continue 等命令,還能進行普通的數學和字符串操作。當然了,還可以用 exec 來調用 Unix 程序。所有這些功能,Tcl 都有。Tcl 在參考書籍 Outerhour[3][4]里有詳細的描述。
Expect 是在 Tcl 基礎上創建起來的,它還提供了一些 Tcl 所沒有的命令。spawn 命令激活一個 Unix 程序來進行交互式的運行。send 命令向進程發送字符串。expect 命令等待進程的某些字符串。expect 支持正規表達式并能同時等待多個字符串,并對每一個字符串執行不同的操作。expect 還能理解一些特殊情況,如超時和遇到文件尾。
expect 命令和 Tcl 的 case 命令的風格很相似。都是用一個字符串去匹配多個字符串。(只要有可能,新的命令總是和已有的 Tcl 命令相似,以使得該語言保持工具族的繼承性)。下面關于 expect 的定義是從手冊 [5] 上摘錄下來的。
expect patlist1 action1 patlist2 action2…..
該命令一直等到當前進程的輸出和以上的某一個模式相匹配,或者等 到時間超過一個特定的時間長度,或者等到遇到了文件的結束為止。

如果最后一個 action 是空的,就可以省略它。
每一個 patlist 都由一個模式或者模式的表 (lists) 組成。如果有一個模式匹配成功,相應的 action 就被執行。執行的結果從 expect 返回。
被精確匹配的字符串 (或者當超時發生時,已經讀取但未進行匹配的字符串) 被存貯在變量 expect_match 里面。如果 patlist 是 eof 或者 timeout, 則發生文件結束或者超時時才執行相應的 action. 一般超時的時值是 10 秒,但可以用類似 set timeout 30 之類的命令把超時時值設定為 30 秒。

下面的一個程序段是從一個有關登錄的腳本里面摘取的。abort 是在腳本的別處定義的過程,而其他的 action 使用類似與 C 語言的 Tcl 原語。
expect *welcome* break
*busy* {print busy;continue}
*failed* abort
timeout abort
模式是通常的 C Shell 風格的正規表達式。模式必須匹配當前進程的從上一個 expect 或者 interact 開始的所有輸出 (所以統配符 * 使用的非常) 的普遍。但是,一旦輸出超過 2000 個字節,前面的字符就會被忘記,這可以通過設定 match_max 的值來改變。
expect 命令確實體現了 expect 語言的最好和最壞的性質。特別是,expect 命令的靈活性是以經常出現令人迷惑的語法做代價。除了關鍵字模式 (比如說 eof,timeout)那些模式表可以包括多個模式。這保證提供了一種方法來區分他們。但是分開這些表需要額外的掃描,如果沒有恰當的用 []括起來,這有可能會把和當成空白字符。由于 Tcl 提供了兩種字符串引用的方法:單引和雙引,情況變的更糟。(在 Tcl 里面,如果不會出現二義性話,沒有必要使用引號)。在 expect 的手冊里面,還有一個獨立的部分來解釋這種復雜性。幸運的是:有一些很好的例子似乎阻止了這種抱怨。但是,這個復雜性很有可能在將來的版本中再度出現。為了增強可讀性,在本文中,提供的腳本都假定雙引號是足夠的。
字符可以使用反斜杠來單獨的引用,反斜杠也被用于對語句的延續,如果不加反斜杠的話,語句到一行的結尾處就結束了。這和 Tcl 也是一致的。Tcl 在發現有開的單引號或者開的雙引號時都會繼續掃描。而且,分號可以用于在一行中分割多個語句。這乍聽起來有點讓人困惑,但是,這是解釋性語言的風格,但是,這確實是 Tcl 的不太漂亮的部分。
5.[callback]
令人非常驚訝的是,一些小的腳本如何的產生一些有用的功能。下面是一個撥電話號碼的腳本。他用來把收費反向,以便使得長途電話對計算機計費。這個腳本用類似“expect callback.exp 12016442332”來激活。其中,腳本的名字便是 callback.exp,而 +1(201)644-2332 是要撥的電話號碼。
#first give the user some time to logout
exec sleep 4
spawn tip modem
expect *connected*
send ATD [index $argv 1]
#modem takes a while to connect
set timeout 60
expect *CONNECT*
第一行是注釋,第二行展示了如何調用沒有交互的 Unix 程序。sleep 4 會使程序阻塞 4 秒,以使得用戶有時間來退出,因為 modem 總是會回叫用戶已經使用的電話號碼。
下面一行使用 spawn 命令來激活 tip 程序,以便使得 tip 的輸出能夠被 expect 所讀取,使得 tip 能從 send 讀輸入。一旦 tip 說它已經連接上,modem 就會要求去撥打大哥電話號碼。(假定 modem 都是賀氏兼容的,但是本腳本可以很容易的修改成能適應別的類型的 modem)。不論發生了什么,expect 都會終止。如果呼叫失敗,expect 腳本可以設計成進行重試,但這里沒有。如果呼叫成功,getty 會在 expect 退出后檢測到 DTR,并且向用戶提示 loging:。(實用的腳本往往提供更多的錯誤檢測)。
這個腳本展示了命令行參數的使用,命令行參數存貯在一個叫做 argv 的表里面(這和 C 語言的風格很象)。在這種情況下,第一個元素就是電話號碼。方括號使得被括起來的部分當作命令來執行,結果就替換被括起來的部分。這也和 C Shell 的風格很象。
這個腳本和一個大約 60K 的 C 語言程序實現的功能相似。

6.[passwd 和一致性檢查]
在前面,我們提到 passwd 程序在缺乏用戶交互的情況下,不能運行,passwd 會忽略 I / O 重定向,也不能嵌入到管道里邊以便能從別的程序或者文件里讀取輸入。這個程序堅持要求真正的與用戶進行交互。因為安全的原因,passwd 被設計成這樣,但結果導致沒有非交互式的方法來檢驗 passwd。這樣一個對系統安全至關重要的程序竟然沒有辦法進行可靠的檢驗,真實具有諷刺意味。
passwd 以一個用戶名作為參數,交互式的提示輸入密碼。下面的 expect 腳本以用戶名和密碼作為參數而非交互式的運行。
spawn oasswd [index $argv 1]
set password [index $argv 2]
expect *password:
send $password
expect *password:
send $password
expect eof
第一行以用戶名做參數啟動 passwd 程序,為方便起見,第二行把密碼存到一個變量里面。和 shell 類似,變量的使用也不需要提前聲明。
在第三行,expect 搜索模式 *password:,其中 * 允許匹配任意輸入,所以對于避免指定所有細節而言是非常有效的。上面的程序里沒有 action, 所以 expect 檢測到該模式后就繼續運行。
一旦接收到提示后,下一行就就把密碼送給當前進程。表明回車。(實際上,所有的 C 的關于字符的約定都支持)。上面的程序中有兩個 expect- send 序列,因為 passwd 為了對輸入進行確認,要求進行兩次輸入。在非交互式程序里面,這是毫無必要的,但由于假定 passwd 是在和用戶進行交互,所以我們的腳本還是這樣做了。
最后,expect eof 這一行的作用是在 passwd 的輸出中搜索文件結束符,這一行語句還展示了關鍵字的匹配。另外一個關鍵字匹配就是 timeout 了,timeout 被用于表示所有匹配的失敗而和一段特定長度的時間相匹配。在這里 eof 是非常有必要的,因為 passwd 被設計成會檢查它的所有 I / O 是否都成功了,包括第二次輸入密碼時產生的最后一個新行。
這個腳本已經足夠展示 passwd 命令的基本交互性。另外一個更加完備的例子回檢查別的一些行為。比如說,下面的這個腳本就能檢查 passwd 程序的別的幾個方面。所有的提示都進行了檢查。對垃圾輸入的檢查也進行了適當的處理。進程死亡,超乎尋常的慢響應,或者別的非預期的行為都進行了處理。
spawn passwd [index $argv 1]
expect eof {exit 1}
timeout {exit 2}
*No such user.* {exit 3}
*New password:
send [index $argv 2
expect eof {exit 4}
timeout {exit 2}
*Password too long* {exit 5}
*Password too short* {exit 5}
*Retype ew password:
send [index $argv 3]
expect timeout {exit 2}
*Mismatch* {exit 6}
*Password unchanged* {exit 7}

expect timeout {exit 2}
* {exit 6}
eof

這個腳本退出時用一個數字來表示所發生的情況。0 表示 passwd 程序正常運行,1 表示非預期的死亡,2 表示鎖定,等等。使用數字是為了簡單起見。expect 返回字符串和返回數字是一樣簡單的,即使是派生程序自身產生的消息也是一樣的。實際上,典型的做法是把整個交互的過程存到一個文件里面,只有當程序的運行和預期一樣的時候才把這個文件刪除。否則這個 log 被留待以后進一步的檢查。
這個 passwd 檢查腳本被設計成由別的腳本來驅動。這第二個腳本從一個文件里面讀取參數和預期的結果。對于每一個輸入參數集,它調用第一個腳本并且把結果和預期的結果相比較。(因為這個任務是非交互的,一個普通的老式 shell 就可以用來解釋第二個腳本)。比如說,一個 passwd 的數據文件很有可能就象下面一樣。
passwd.exp 3 bogus – –
passwd.exp 0 fred abledabl abledabl
passwd.exp 5 fred abcdefghijklm –
passwd.exp 5 fred abc –
passwd.exp 6 fred foobar bar
passwd.exp 4 fred ^C –
第一個域的名字是要被運行的回歸腳本。第二個域是需要和結果相匹配的退出值。第三個域就是用戶名。第四個域和第五個域就是提示時應該輸入的密碼。減號僅僅表示那里有一個域,這個域其實絕對不會用到。在第一個行中,bogus 表示用戶名是非法的,因此 passwd 會響應說:沒有此用戶。expect 在退出時會返回 3,3 恰好就是第二個域。在最后一行中,^C 就是被切實的送給程序來驗證程序是否恰當的退出。
通過這種方法,expect 可以用來檢驗和調試交互式軟件,這恰恰是 IEEE 的 POSIX 1003.2(shell 和工具)的一致性檢驗所要求的。進一步的說明請參考 Libes[6]。
7.[rogue 和偽終端]
Unix 用戶肯定對通過管道來和其他進程相聯系的方式非常的熟悉 (比如說:一個 shell 管道)。expect 使用偽終端來和派生的進程相聯系。偽終端提供了終端語義以便程序認為他們正在和真正的終端進行 I / O 操作。
比如說,BSD 的探險游戲 rogue 在生模式下運行,并假定在連接的另一端是一個可尋址的字符終端??梢杂?expect 編程,使得通過使用用戶界面可以玩這個游戲。
rogue 這個探險游戲首先提供給你一個有各種物理屬性,比如說力量值,的角色。在大部分時間里,力量值都是 16,但在幾乎每 20 次里面就會有一個力量值是 18。很多的 rogue 玩家都知道這一點,但沒有人愿意啟動程序 20 次以獲得一個好的配置。下面的這個腳本就能達到這個目的。
for {} {1} {} {
spawn rogue
expect *Str:18* break
*Str:16*
close
wait
}
interact
第一行是個 for 循環,和 C 語言的控制格式很象。rogue 啟動后,expect 就檢查看力量值是 18 還是 16,如果是 16,程序就通過執行 close 和 wait 來退出。這兩個命令的作用分別是關閉和偽終端的連接和等待進程退出。rogue 讀到一個文件結束符就推出,從而循環繼續運行,產生一個新的 rogue 游戲來檢查。
當一個值為 18 的配置找到后,控制就推出循環并跳到最后一行腳本。interact 把控制轉移給用戶以便他們能夠玩這個特定的游戲。
想象一下這個腳本的運行。你所能真正看到的就是 20 或者 30 個初始的配置在不到一秒鐘的時間里掠過屏幕,最后留給你的就是一個有著很好配置的游戲。唯一比這更好的方法就是使用調試工具來玩游戲。
我們很有必要認識到這樣一點:rogue 是一個使用光標的圖形游戲。expect 程序員必須了解到:光標的運動并不一定以一種直觀的方式在屏幕上體現。幸運的是,在我們這個例子里,這不是一個問題。將來的對 expect 的改進可能會包括一個內嵌的能支持字符圖形區域的終端模擬器。
8.[ftp]
我們使用 expect 寫第一個腳本并沒有打印出 Hello,World。實際上,它實現了一些更有用的功能。它能通過非交互的方式來運行 ftp。ftp 是用來在支持 TCP/IP 的網絡上進行文件傳輸的程序。除了一些簡單的功能,一般的實現都要求用戶的參與。
下面這個腳本從一個主機上使用匿名 ftp 取下一個文件來。其中,主機名是第一個參數。文件名是第二個參數。
spawn ftp [index $argv 1]
expect *Name*
send anonymous
expect *Password:*
send [exec whoami]
expect *ok*ftp *
send get [index $argv 2]
expect *ftp *
上面這個程序被設計成在后臺進行 ftp。雖然他們在底層使用和 expect 類似的機制,但他們的可編程能力留待改進。因為 expect 提供了高級語言,你可以對它進行修改來滿足你的特定需求。比如說,你可以加上以下功能:
:堅持--如果連接或者傳輸失敗,你就可以每分鐘或者每小時,甚
至可以根據其他因素,比如說用戶的負載,來進行不定期的
重試。
:通知--傳輸時可以通過 mail,write 或者其他程序來通知你,甚至
可以通知失敗。
:初始化-每一個用戶都可以有自己的用高級語言編寫的初始化文件
(比如說,.ftprc)。這和 C shell 對.cshrc 的使用很類似。
expect 還可以執行其他的更復雜的任務。比如說,他可以使用 McGill 大學的 Archie 系統。Archie 是一個匿名的 Telnet 服務,它提供對描述 Internet 上可通過匿名 ftp 獲取的文件的數據庫的訪問。通過使用這個服務,腳本可以詢問 Archie 某個特定的文件的位置,并把它從 ftp 服務器上取下來。這個功能的實現只要求在上面那個腳本中加上幾行就可以。
現在還沒有什么已知的后臺 -ftp 能夠實現上面的幾項功能,能不要說所有的功能了。在 expect 里面,它的實現卻是非常的簡單?!皥猿帧钡膶崿F只要求在 expect 腳本里面加上一個循環。“通知”的實現只要執行 mail 和 write 就可以了。“初始化文件”的實現可以使用一個命令,source .ftprc,就可以了,在.ftprc 里面可以有任何的 expect 命令。
雖然這些特征可以通過在已有的程序里面加上鉤子函數就可以,但這也不能保證每一個人的要求都能得到滿足。唯一能夠提供保證的方法就是提供一種通用的語言。一個很好的解決方法就是把 Tcl 自身融入到 ftp 和其他的程序中間去。實際上,這本來就是 Tcl 的初衷。在還沒有這樣做之前,expect 提供了一個能實現大部分功能但又不需要任何重寫的方案。
9.[fsck]
fsck 是另外一個缺乏足夠的用戶接口的例子。fsck 幾乎沒有提供什么方法來預先的回答一些問題。你能做的就是給所有的問題都回答 yes 或者都回答 no。
下面的程序段展示了一個腳本如何的使的自動的對某些問題回答 yes,而對某些問題回答 no。下面的這個腳本一開始先派生 fsck 進程,然后對其中兩種類型的問題回答 yes,而對其他的問題回答 no。
for {} {1} {} {
expect
eof break
*UNREF FILE*CLEAR? {send r}
*BAD INODE*FIX? {send y}
*? {send n}
}
在下面這個版本里面,兩個問題的回答是不同的。而且,如果腳本遇到了什么它不能理解的東西,就會執行 interact 命令把控制交給用戶。用戶的擊鍵直接交給 fsck 處理。當執行完后,用戶可以通過按 + 鍵來退出或者把控制交還給 expect。如果控制是交還給腳本了,腳本就會自動的控制進程的剩余部分的運行。
for {} {1} {}{
expect
eof break
*UNREF FILE*CLEAR? {send y}
*BAD INODE*FIX? {send y}
*? {interact +}
}
如果沒有 expect,fsck 只有在犧牲一定功能的情況下才可以非交互式的運行。fsck 幾乎是不可編程的,但它卻是系統管理的最重要的工具。許多別的工具的用戶接口也一樣的不足。實際上,正是其中的一些程序的不足導致了 expect 的誕生。
10.[控制多個進程:作業控制]
expect 的作業控制概念精巧的避免了通常的實現困難。其中包括了兩個問題:一個是 expect 如何處理經典的作業控制,即當你在終端上按下 ^Z 鍵時 expect 如何處理;另外一個就是 expect 是如何處理多進程的。
對第一個問題的處理是:忽略它。expect 對經典的作業控制一無所知。比如說,你派生了一個程序并且發送一個 ^Z 給它,它就會停下來(這是偽終端的完美之處) 而 expect 就會永遠的等下去。
但是,實際上,這根本就不成一個問題。對于一個 expect 腳本,沒有必要向進程發送 ^Z。也就是說,沒有必要停下一個進程來。expect 僅僅是忽略了一個進程,而把自己的注意力轉移到其他的地方。這就是 expect 的作業控制思想,這個思想也一直工作的很好。
從用戶的角度來看是象這樣的:當一個進程通過 spawn 命令啟動時,變量 spawn_id 就被設置成某進程的描述符。由 spawn_id 描述的進程就被認為是當前進程。(這個描述符恰恰就是偽終端文件的描述符,雖然用戶把它當作一個不透明的物體)。expect 和 send 命令僅僅和當前進程進行交互。所以,切換一個作業所需要做的僅僅是把該進程的描述符賦給 spawn_id。
這兒有一個例子向我們展示了如何通過作業控制來使兩個 chess 進程進行交互。在派生完兩個進程之后,一個進程被通知先動一步。在下面的循環里面,每一步動作都送給另外一個進程。其中,read_move 和 write_move 兩個過程留給讀者來實現。(實際上,它們的實現非常的容易,但是,由于太長了所以沒有包含在這里)。
spawn chess ;# start player one
set id1 $spawn_id
expect Chess
send first ;# force it to go first
read_move
spawn chess ;# start player two
set id2 $spawn_id
expect Chess

for {} {1} {}{
send_move
read_move
set spawn_id $id1

send_move
read_move
set spawn_id $id2
}
有一些應用程序和 chess 程序不太一樣,在 chess 程序里,的兩個玩家輪流動。下面這個腳本實現了一個冒充程序。它能夠控制一個終端以便用戶能夠登錄和正常的工作。但是,一旦系統提示輸入密碼或者輸入用戶名的時候,expect 就開始把擊鍵記下來,一直到用戶按下回車鍵。這有效的收集了用戶的密碼和用戶名,還避免了普通的冒充程序的 Incorrect password-tryagain。而且,如果用戶連接到另外一個主機上,那些額外的登錄也會被記錄下來。
spawn tip /dev/tty17 ;# open connection to
set tty $spawn_id ;# tty to be spoofed
spawn login
set login $spawn_id
log_user 0

for {} {1} {} {
set ready [select $tty $login]

case $login in $ready {
set spawn_id $login
expect
{*password* *login*}{
send_user $expect_match
set log 1
}
* ;# ignore everything else
set spawn_id $tty;
send $expect_match
}
case $tty in $ready {
set spawn_id $tty
expect * * {
if $log {
send_user $expect_match
set log 0
}
}
* {
send_user $expect_match
}
set spawn_id $login;
send $expect_match
}
}

這個腳本是這樣工作的。首先連接到一個 login 進程和終端。缺省的,所有的對話都記錄到標準輸出上 (通過 send_user)。因為我們對此并不感興趣,所以,我們通過命令 log_user 0 來禁止這個功能。(有很多的命令來控制可以看見或者可以記錄的東西)。
在循環里面,select 等待終端或者 login 進程上的動作,并且返回一個等待輸入的 spawn_id 表。如果在表里面找到了一個值的話,case 就執行一個 action。比如說,如果字符串 login 出現在 login 進程的輸出中,提示就會被記錄到標準輸出上,并且有一個標志被設置以便通知腳本開始記錄用戶的擊鍵,直至用戶按下了回車鍵。無論收到什么,都會回顯到終端上,一個相應的 action 會在腳本的終端那一部分執行。
這些例子顯示了 expect 的作業控制方式。通過把自己插入到對話里面,expect 可以在進程之間創建復雜的 I / O 流??梢詣摻ǘ嗌瘸?,復用扇入的,動態的數據相關的進程圖。
相比之下,shell 使得它自己一次一行的讀取一個文件顯的很困難。shell 強迫用戶按下控制鍵(比如,^C,^Z) 和關鍵字 (比如 fg 和 bg) 來實現作業的切換。這些都無法從腳本里面利用。相似的是:以非交互方式運行的 shell 并不處理“歷史記錄”和其他一些僅僅為交互式使用設計的特征。這也出現了和前面哪個 passwd 程序的相似問題。相似的,也無法編寫能夠回歸的測試 shell 的某些動作的 shell 腳本。結果導致 shell 的這些方面無法進行徹底的測試。
如果使用 expect 的話,可以使用它的交互式的作業控制來驅動 shell。一個派生的 shell 認為它是在交互的運行著,所以會正常的處理作業控制。它不僅能夠解決檢驗處理作業控制的 shell 和其他一些程序的問題。還能夠在必要的時候,讓 shell 代替 expect 來處理作業。可以支持使用 shell 風格的作業控制來支持進程的運行。這意味著:首先派生一個 shell,然后把命令送給 shell 來啟動進程。如果進程被掛起,比如說,發送了一個 ^Z,進程就會停下來,并把控制返回給 shell。對于 expect 而言,它還在處理同一個進程 (原來那個 shell)。
expect 的解決方法不僅具有很大的靈活性,它還避免了重復已經存在于 shell 中的作業控制軟件。通過使用 shell,由于你可以選擇你想派生的 shell,所以你可以根據需要獲得作業控制權。而且,一旦你需要(比如說檢驗的時候),你就可以驅動一個 shell 來讓這個 shell 以為它正在交互式的運行。這一點對于在檢測到它們是否在交互式的運行之后會改變輸出的緩沖的程序來說也是很重要的。
為了進一步的控制,在 interact 執行期間,expect 把控制終端(是啟動 expect 的那個終端,而不是偽終端) 設置成生模式以便字符能夠正確的傳送給派生的進程。當 expect 在沒有執行 interact 的時候,終端處于熟模式下,這時候作業控制就可以作用于 expect 本身。
11.[交互式的使用 expect]
在前面,我們提到可以通過 interact 命令來交互式的使用腳本?;旧蟻碚f,interact 命令提供了對對話的自由訪問,但我們需要一些更精細的控制。這一點,我們也可以使用 expect 來達到,因為 expect 從標準輸入中讀取輸入和從進程中讀取輸入一樣的簡單。但是,我們要使用 expect_user 和 send_user 來進行標準 I /O,同時不改變 spawn_id。
下面的這個腳本在一定的時間內從標準輸入里面讀取一行。這個腳本叫做 timed_read,可以從 csh 里面調用,比如說,set answer= timed_read 30 就能調用它。
#!/usr/local/bin/expect -f
set timeout [index $argv 1]
expect_user *
send_user $expect_match
第三行從用戶那里接收任何以新行符結束的任何一行。最后一行把它返回給標準輸出。如果在特定的時間內沒有得到任何鍵入,則返回也為空。
第一行支持 #! 的系統直接的啟動腳本。(如果把腳本的屬性加上可執行屬性則不要在腳本前面加上 expect)。當然了腳本總是可以顯式的用 expect scripot 來啟動。在 - c 后面的選項在任何腳本語句執行前就被執行。比如說,不要修改腳本本身,僅僅在命令行上加上 -c trace…,該腳本可以加上 trace 功能了 (省略號表示 trace 的選項)。
在命令行里實際上可以加上多個命令,只要中間以 分開就可以了。比如說,下面這個命令行:
expect -c set timeout 20;spawn foo;expect
一旦你把超時時限設置好而且程序啟動之后,expect 就開始等待文件結束符或者 20 秒的超時時限。如果遇到了文件結束符(EOF),該程序就會停下來,然后 expect 返回。如果是遇到了超時的情況,expect 就返回。在這兩中情況里面,都隱式的殺死了當前進程。
如果我們不使用 expect 而來實現以上兩個例子的功能的話,我們還是可以學習到很多的東西的。在這兩中情況里面,通常的解決方案都是 fork 另一個睡眠的子進程并且用 signal 通知原來的 shell。如果這個過程或者讀先發生的話,shell 就會殺司那個睡眠的進程。傳遞 pid 和防止后臺進程產生啟動信息是一個讓除了高手級 shell 程序員之外的人頭痛的事情。提供一個通用的方法來象這樣啟動多個進程會使 shell 腳本非常的復雜。所以幾乎可以肯定的是,程序員一般都用一個專門 C 程序來解決這樣一個問題。
expect_user,send_user,send_error(向標準錯誤終端輸出) 在比較長的,用來把從進程來的復雜交互翻譯成簡單交互的 expect 腳本里面使用的比較頻繁。在參考 [7] 里面,Libs 描述怎樣用腳本來安全的包裹(wrap)adb,怎樣把系統管理員從需要掌握 adb 的細節里面解脫出來,同時大大的降低了由于錯誤的擊鍵而導致的系統崩潰。
一個簡單的例子能夠讓 ftp 自動的從一個私人的帳號里面取文件。在這種情況里,要求提供密碼。即使文件的訪問是受限的,你也應該避免把密碼以明文的方式存儲在文件里面。把密碼作為腳本運行時的參數也是不合適的,因為用 ps 命令能看到它們。有一個解決的方法就是在腳本運行的開始調用 expect_user 來讓用戶輸入以后可能使用的密碼。這個密碼必須只能讓這個腳本知道,即使你是每個小時都要重試 ftp。
即使信息是立即輸入進去的,這個技巧也是非常有用。比如說,你可以寫一個腳本,把你每一個主機上不同的帳號上的密碼都改掉,不管他們使用的是不是同一個密碼數據庫。如果你要手工達到這樣一個功能的話,你必須 Telnet 到每一個主機上,并且手工輸入新的密碼。而使用 expect, 你可以只輸入密碼一次而讓腳本來做其它的事情。
expect_user 和 interact 也可以在一個腳本里面混合的使用??紤]一下在調試一個程序的循環時,經過好多步之后才失敗的情況。一個 expect 腳本可以驅動哪個調試器,設置好斷點,執行該程序循環的若干步,然后將控制返回給鍵盤。它也可以在返回控制之前,在循環體和條件測試之間來回的切換。

看完了這篇文章,相信你對“expect 如何處理 htpasswd 交互”有了一定的了解,如果想了解更多相關知識,歡迎關注丸趣 TV 行業資訊頻道,感謝各位的閱讀!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-25發表,共計13660字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
主站蜘蛛池模板: 双江| 无棣县| 枞阳县| 寿阳县| 陈巴尔虎旗| 应用必备| 平昌县| 黄梅县| 庆云县| 澄迈县| 朝阳区| 长阳| 托克逊县| 迁安市| 颍上县| 闻喜县| 大姚县| 灌南县| 阳高县| 都匀市| 崇义县| 隆林| 蕉岭县| 玉田县| 慈溪市| 耒阳市| 桓仁| 于都县| 宜昌市| 桐梓县| 鄂尔多斯市| 蒙自县| 大城县| 通州市| 招远市| 宁海县| 南和县| 永吉县| 耿马| 镇安县| 壤塘县|