天天看點

SHELL腳本之另一種腳本EXPECT

“shell是世界上最好的腳本語言!”🌚🌚🌚

shell腳本雖然可以很友善的幫我處理一些瑣碎的問題,但同時也有它的缺點:shell腳本是一種無互動式的腳本

什麼叫無互動式呢,比如說删除這個指令

[[email protected] ~]# rm test
rm:是否删除普通檔案 "test"?
           

在删除一個檔案時,系統會給一條互動資訊詢問是否要删除檔案,是以删除一個檔案需要有兩個操作:删除->确認删除(當然你也可以加-f來強制删除就不會有這個互動過程了,這裡隻是舉一個例子),而shell執行指令時實際上隻能一條一條的執行,并不能處理這些互動過程

是以這就引出了本文的主角:expect,一種互動式的腳本工具

其他我就不多說了,直接來将expect怎麼使用吧

  • 安裝:

    yum install expect

  • 編寫expect腳本:
    • 腳本名一般以

      .exp

      結尾
    • 第一行為

      #!/usr/bin/expect

  • 定義變量:
    • set 變量名 值

    • set 變量名 [lindex $argv 0]

      :從指令參數數組中取值
    • 特殊變量:
      • $argc

        :參數個數,相當于shell中的

        $#

      • $argv

        :所有參數的數組,索引從0開始
  • 語句:
    • set 定義變量

      • set timeout 300

        :将逾時時間設定成300(秒)
    • spawn COMMAND

      :監控指令的輸出
    • expect “STRING” { send “STRING” }

      :捕獲輸出,并執行相應指令
    • send “STRING\r”

      :發送“STRING”,比如删除檔案時需要回複yes表示确認删除,就可以寫

      send “yes\r”

      ,注意最後需要換行,不然輸出結果看起來會比較亂
    • send_user “STRING”

      :執行expect時前台會被占用,這裡相當于在執行完腳本中的某一個任務時發給終端的一條提示,相當于shell中的

      echo

    • exp_continue

      :繼續捕獲輸出,expect用{}框起來的塊中可以實作類似case的判斷效果,這裡的exp_continue就相當于case語句中每一判斷條件的break
    • interact

      :暫停腳本的執行,将控制權交還給使用者,直到使用者
    • exit

      :退出腳本
    • expect eof

      :捕獲退出信号,若捕獲不到則會阻塞等待,逾時自動退出

下面是一些相關例子:

模拟ftp登入并下載下傳檔案

  • 工作準備:
    • 關閉防火牆:

      iptable -F

    • yum install vsftpd

    • systemctl restart vsftpd

    • cp /etc/fstab /var/ftp

    • yum install ftp

#!/usr/bin/expect

set ip [lindex $argv 0]
set name "ftp"
set pass ""
set file "fstab"

spawn ftp $ip
expect "Name"
	send "$name\r"
expect "Password"
	send "$pass\r"
expect ">" {
	send "get $file ftp_$file\r"
	send "exit\r"
}
expect eof
send_user "ALL COMMAND FINISHDED\n"
           

測試用例:

[[email protected] ~]# ./ftp.exp 127.0.0.1
spawn ftp 127.0.0.1
Connected to 127.0.0.1 (127.0.0.1).
220 (vsFTPd 3.0.2)
Name (127.0.0.1:root): ftp
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> get fstab ftp_fstab
local: ftp_fstab remote: fstab
227 Entering Passive Mode (127,0,0,1,246,62).
150 Opening BINARY mode data connection for fstab (501 bytes).
226 Transfer complete.
501 bytes received in 0.000192 secs (2609.38 Kbytes/sec)
ftp> exit
221 Goodbye.
ALL COMMAND FINISHDED
[[email protected] ~]# 
[[email protected] ~]# ll | grep 'ftp_'
-rw-r--r--. 1 root root      501 3月   5 22:28 ftp_fstab
           

用shell腳本批量分發公鑰(将所有)

  1. 建立密鑰分發expect腳本

    key.exp

#!/usr/bin/expect 
set timeout 300
set password "redhat"
set ip [lindex $argv 0]
spawn ssh-copy-id [email protected]$ip
expect {
	"yes/no"  {
		send "yes\r"
		exp_continue
	}
	"password: " {
		send "$password\r"
		exp_continue
	}		
	"No route to host" {
		exit 1
	}		
	eof
}
           
  1. 建立shell腳本,調用expect
#!/bin/bash

. /etc/init.d/functions


for i in `cat /root/ip.txt`; do
	expect /root/key.exp $i > /dev/null 2>&1
 	if [ $? -eq 0 ]; then
        	action "$i" /bin/true
	else
        	action "$i" /bin/false
	fi
done
           

繼續閱讀