[Linux] expect用法舉例

expect有助於自動化腳本中的交互過程的自動輸入,例如遠程登錄需要輸入確認信息、密碼,安裝腳本需要輸入確認信息、用戶名、密碼、選擇配置選項等等。

expect內部命令中的expect可以匹配一個給定的字符串,匹配上了可以再使用send命令返回一個字符串。

[例1] 使用"-c"選項,從命令行執行expect腳本

[root@xxx test]# expect -c 'expect "\n" {send "pressed enter\n"}'

pressed enter
[root@xxx test]# 
[root@xxx test]# expect -c 'expect "hi" {send "You said hi\n"}'
hi
You said hi
[root@xxx test]# expect -c 'expect "hi" {send "You said hi\n"}'
high
You said hi
[root@xxx test]#

再看一個ssh登錄的例子,

[例2-1] ssh登錄主機,test.exp內容如下(主機名和密碼寫在腳本中,執行完成後退出)

#!/usr/bin/expect

set ipaddr "localhost"
set passwd "iampasswd"

spawn ssh root@$ipaddr

expect {
"yes/no" { send "yes\r"; exp_continue}
"password:" { send "$passwd\r" }
}

expect "]# "
send "cd /tmp/test;touch a.txt\r"

send "exit\r"

expect eof
exit

執行結果:

[root@xxx test]# ./test.exp
spawn ssh root@localhost
root@localhost's password:
Last login: Wed Mar  4 16:07:11 2020 from localhost
[root@xxx ~]# cd /tmp/test;touch a.txt
[root@xxx test]# exit
logout
Connection to localhost closed.
[root@xxx test]#

檢查當前路徑下已創建a.txt

[root@xxx test]# ls -l
total 4
-rw-r--r-- 1 root root   0 Mar  4 16:09 a.txt
-rwxr-xr-x 1 root root 274 Mar  4 16:09 test.exp
[root@xxx test]#

說明:

1. #!/usr/bin/expect 
首行告訴操作系統腳本里的代碼使用那一個shell來執行。這裏的expect其實和linux下的bash類似。
可以使用which命令查看其位置:
# which expect
/usr/bin/expect

2. set timeout 5 

設置超時時間5秒。"timeout -1" 爲永不超時。

3. set passwd "iampasswd"
給變量passwd賦值,使用$passwd引用

4. spawn ssh root@$ipaddr 
spawn是進入expect環境後纔可以執行的expect內部命令。
其主要功能是給ssh運行進程加個殼,用來傳遞交互指令。 

5. expect "password:" 
expect也是expect的一個內部命令。
其作用時判斷上次輸出結果是否包含字符串"password:",包含則立即返回,否則就等待超時後返回。 

6. send "$passwd\r" 
這裏就是執行交互動作,與手工輸入密碼的動作等效。 
注意命令字符串的結尾要加上"\r"。

7. exp_continue的用法
可以繼續執行下面的匹配。

8. expect eof
使用expect eof,登錄後執行一段命令退出終端。執行完成後如果需要保持交互狀態可使用interact 。

9. interact 
執行完成後保持交互狀態,把控制權交給控制檯,這個時候就可以手工操作了。
如果沒有這一句登錄完成後會退出。 

[例2-2] ssh登錄主機,test2.exp內容如下(主機名和密碼通過參數傳給腳本,執行完成後留在遠程終端)

#!/usr/bin/expect -f

set ipaddress [lindex $argv 0]
set passwd [lindex $argv 1]

set timeout 10

spawn ssh root@$ipaddress

expect {
"yes/no" { send "yes\r";exp_continue }
"password:" { send "$passwd\r" }
}

expect "*from*"
send "cd /tmp;touch b.txt\r"

interact

執行log如下,並且創建了文件b.txt

[root@xxx test]# ./test2.exp 192.168.22.22 iampasswd
spawn ssh [email protected]
[email protected]'s password:
Last login: Wed Mar  4 10:21:42 2020 from 192.168.11.11
cd /tmp;touch b.txt
[root@aaa22 ~]# cd /tmp;touch b.txt
[root@aaa22 tmp]#           => 停留在遠程終端
[root@aaa22 tmp]#
[root@aaa22 tmp]# ls -l b.txt  => 檢查是否生成文件b.txt
-rw-r--r-- 1 root root 0 Mar  4 17:25 b.txt
[root@aaa22 tmp]#

說明:

10.$argv 參數數組
expect腳本可以接受從bash傳遞過來的參數,可以使用[lindex $argv n]獲得,n從0開始,分別表示第1個參數、第2個參數……

$argc 存儲了參數個數,args被結構化成一個列表存在argv。$argv0 被初始化爲腳本名字。
如果在第一行(#!那行)使用-d (debug參數),可以在運行的時候輸出一些很有用的信息,例如

argv[0] = /usr/bin/expect argv[1] = -d argv[2] = ./test2.exp argv[3] = 192.168.22.22 argv[4] = iampasswd

[root@xxx test]# ./test2.exp 192.168.22.22 iampasswd
expect version 5.44.1.15
argv[0] = /usr/bin/expect  argv[1] = -d  argv[2] = ./test2.exp  argv[3] = 192.168.22.22  argv[4] = iampasswd
set argc 2
set argv0 "./test2.exp"
set argv " 192.168.22.22 iampasswd"
executing commands from command file ./test2.exp
……

$argc爲命令行參數的個數,$argv0爲腳本名字本身,$argv爲命令行參數。
[lindex $argv 0] 或 [lrange $argv 0 0]表示第1個參數,[lrange $argv 0 4]爲第一個到第五個參數。
注意:$argv不包含腳本名字本身。

 

[例3] sftp遠程連接服務器取包

先看看手動執行命令的記錄

[root@aaa ~]# sftp [email protected]
[email protected]'s password:
Connected to 192.168.11.11.
sftp> get haha.tar
Fetching /root/haha.tar to haha.tar
/root/SCA-NR-19.4.tar.gz            100%  47MB  25.6MB/s   00:02
sftp>
sftp> get abc.txt
File "/root/abc.txt" not found.
sftp>
sftp> exit
[root@aaa~]#

選定匹配的關鍵字,可以編輯如下腳本sftpfetchpkg.sh

#!/usr/bin/expect -f  
set user "root"
set ip "192.168.11.11"
set passwd "iampasswd" 
set filepath [lindex $argv 0 ]
set timeout 60  

spawn sftp $user@$ip   
expect {
"*assword:*"  {send "$passwd\r;exp_continue" }
"sftp>"  {send "get $filepath\r" }
}
expect "100%" {send "exit\r"}
expect eof

成功取包打屏如下,

[root@aaa test]# ./sftpfetchpkg.sh /root/haha.tar
spawn sftp [email protected]
Connecting to 192.168.11.11...
[email protected]'s password:
sftp> get /root/haha.tar
Fetching /root/haha.tar to haha.tar
sftp> [root@aaa test]#

要取的包不存在打屏如下,

[root@aaa test]# ./sftpfetchpkg.sh /root/wakaka.tar
spawn sftp [email protected]
Connecting to 192.168.11.11...
[email protected]'s password:
sftp> get /root/wakaka.tar
Couldn't stat remote file: No such file or directory
File "/root/wakaka.tar" not found.
sftp> [root@aaa test]#

擴展:python中使用expect -> Pexpect 模塊使用說明 https://www.jianshu.com/p/cfd163200d12

參考文檔:
expect用法  https://www.cnblogs.com/iloveyoucc/archive/2012/05/11/2496433.html
shell中expect介紹  https://www.cnblogs.com/yxh168/p/9028122.html
Shell腳本學習之expect命令  https://www.cnblogs.com/lixigang/articles/4849527.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章