shell結合expect寫的批量scp腳本工具

在部署一個任務時,其中有一項必須的過程就是將一些文件,如安裝包發送到大量的服務器上去。雖然已有宇哥的腳本可用:通過paramiko模塊提供的ssh和scp功能編寫的python腳本。但我到現在還在對python的恐懼之中(雖然已經在空閒時間努力去學習了),所以使用了shell和expect腳本結合的方式,寫了這個批量scp的腳本工具。

expect用於自動化地執行linux環境下的命令行交互任務,例如scp、ssh之類需要用戶手動輸入密碼然後確認的任務。有了這個工具,定義在scp過程中可能遇到的情況,然後編寫相應的處理語句,就可以自動地完成scp操作了。

需要expect工具的話可以在linux環境中使用apt-get或pacman這些包管理工具去獲取安裝,或是到expect開源項目的網站:http://expect.sourceforge.net/ 來獲取。

安裝expect之後,可以嘗試使用以下的代碼來完成對單個服務器的scp任務:

複製代碼代碼如下:

#!/usr/bin/expect
set timeout 10
set host [lindex $argv 0]
set username [lindex $argv 1]
set password [lindex $argv 2]
set src_file [lindex $argv 3]
set dest_file [lindex $argv 4]
spawn scp $src_file $username@$host:$dest_file
expect {
"(yes/no)?"
  {
   send "yes\n"
   expect "*assword:" { send "$password\n"}
}
"*assword:"
{
send "$password\n"
}
}
expect "100%"
expect eof



注意代碼剛開始的第一行,指定了expect的路徑,與shell腳本相同,這一句指定了程序在執行時到哪裏去尋找相應的啓動程序。代碼剛開始還設定了timeout的時間爲10秒,如果在執行scp任務時遇到了代碼中沒有指定的異常,則在等待10秒後該腳本的執行會自動終止。

從以上代碼剛開始的幾行可以看出,我爲這個腳本設置了5個需要手動輸入的參數,分別爲:目標主機的IP、用戶名、密碼、本地文件路徑、目標主機中的文件路徑。如果將以上腳本保存爲expect_scp文件,則在shell下執行時需要按以下的規範來輸入命令:
./expect_scp 192.168.75.130 root 123456 /root/src_file /root/dest_file

以上的命令執行後,將把本地/root目錄下的src_file文件拷貝到用戶名爲root,密碼爲123456的主機192.168.75.130中的/root下,同時還將這個源文件重命名爲dest_file。

spawn代表在本地終端執行的語句,在該語句開始執行後,expect開始捕獲終端的輸出信息,然後做出對應的操作。expect代碼中的捕獲的(yes/no)內容用於完成第一次訪問目標主機時保存密鑰的操作。有了這一句,scp的任務減少了中斷的情況。代碼結尾的expect eof與spawn對應,表示捕獲終端輸出信息的終止。

有了這段expect的代碼,還只能完成對單個遠程主機的scp任務。如果需要實現批量scp的任務,則需要再寫一個shell腳本來調用這個expect腳本。

shell腳本:


複製代碼代碼如下:

#!/bin/sh
list_file=$1
src_file=$2
dest_file=$3
cat $list_file | while read line
do
  host_ip=`echo $line | awk '{print $1}'`
  username=`echo $line | awk '{print $2}'`
  password=`echo $line | awk '{print $3}'`
  echo "$host_ip"
  ./expect_scp $host_ip $username $password $src_file $dest_file
done


指定了3個參數:列表文件的位置、本地源文件路徑、遠程主機目標文件路徑。需要說明的是其中的列表文件指定了遠程主機ip、用戶名、密碼,這些信息需要寫成以下的格式:
IP username password

中間用空格或tab鍵來分隔,多臺主機的信息需要寫多行內容,如:
192.168.75.130 root 123456
192.168.75.131 knktc testpass

這樣就指定了兩臺遠程主機的信息。注意,如果遠程主機密碼中有“$”、“#”這類特殊字符的話,在編寫列表文件時就需要在這些特殊字符前加上轉義字符,否則expect在執行時會輸入錯誤的密碼。

對於這個shell腳本,保存爲batch_scp.sh文件,與剛纔保存的expect_scp文件和列表文件(就定義爲hosts.list文件吧)放到同一目錄下,執行時按照以下方式輸入命令就可以了:
./batch_scp.sh ./hosts.list /root/src_file /root/destfile
用這兩個腳本文件,就可以簡單地完成批量scp的任務了。
其實批量scp的任務並不難,但是批量ssh的任務可能就會遇到麻煩了。

添加一例:

#!/usr/bin/expect
for{setip 11} {$ip <= 20} {incr ip} {  # 假設有10臺機器
# 複製腳本到各臺機器上
spawn scp-P58422 /root/bin/myscript.sh "[email protected].$ip:/root/bin/myscript.sh"
expect "*password:"
send "123456\r"
send "exit\r"
# 在各臺機器上執行命令
spawn ssh-p58422 -t -o StrictHostKeyChecking=no "[email protected].$ip"
expect "*password:"
send "123456\r"
expect "*]#"
send "/root/bin/myscript.sh\r"# 執行腳本
expect "*]#"
send "echo \"01 */1 * * * root /root/bin/myscript.sh\" >> /etc/crontab \r"# 放入crontab內
expect "*]#"
send "service crond reload \r"# 重啓crond服務
send "exit\r"


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