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