第二十章 Shell程式設計(下)
20.27 分發系統介紹
20.28 expect指令碼遠端登入
#! /usr/bin/expect
set host "192.168.93.128"
set passwd "123456"
spawn ssh [email protected]$host
expect {
"yes/no" { send "yes\r"; exp_continue}
"assword:" { send "$passwd\r" }
}
interact
set
定義變數spawn
執行命令expect
使用expect語句進行互動\r
表示回車exp_contunue
interact
表示繼續互動expect eof
表示停留遠端機器上一會兒再退出
20.29 expect指令碼遠端執行命令
#!/usr/bin/expect
set user "root"
set passwd "123456"
spawn ssh [email protected]
expect {
"yes/no" { send "yes\r"; exp_continue}
"password:" { send "$passwd\r" }
}
expect "]*"
send "touch /tmp/12.txt\r"
expect "]*"
send "echo 1212 > /tmp/12.txt\r"
expect "]*"
send "exit\r"
20.30 expect指令碼傳遞引數
#!/usr/bin/expect
set user [lindex $argv 0]
set host [lindex $argv 1]
set passwd "123456"
set cm [lindex $argv 2]
spawn ssh [email protected]$host
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect "]*"
send "$cm\r"
expect "]*"
send "exit\r"
[lindex $argv 0]表示要輸入的第一個引數 如此類推
當要輸入引數裡面有多個命令是需要用""雙引號括起來並使用;分號分開
可以在命令列的後面增加set timeout
來指定命令的超時時間 -1
為永遠
20.31 expect指令碼同步檔案
#!/usr/bin/expect
set passwd "123456"
spawn rsync -av [email protected]:/tmp/12.txt /tmp/
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof
20.32 expect指令碼指定host和要同步的檔案
#!/usr/bin/expect
set passwd "123456"
set host [lindex $argv 0]
set file [lindex $argv 1]
spawn rsync -av $file [email protected]$host:$file
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof
20.33 構建檔案分發系統
[[email protected] shell]# cat rsync.expect
#!/usr/bin/expect
set passwd "123456"
set host [lindex $argv 0]
set file [lindex $argv 1]
spawn rsync -avR --files-from=$file / [email protected]$host:/
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof
[[email protected] tmp]# cat ip.list
192.168.93.128
[[email protected] tmp]# cat list.txt
/tmp/12.txt
/root/shell/qq.txt
20.34 批量遠端執行命令
[[email protected] tmp]# cat exe.expect
#!/usr/bin/expect
set host [lindex $argv 0]
set passwd "123456"
set cm [lindex $argv 1]
spawn ssh [email protected]$host
expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect "]*"
send "$cm\r"
expect "]*"
send "exit\r"
[[email protected] tmp]# cat /tmp/ip.list
192.168.93.128
課堂串講
20.27 分發系統介紹
20.28 expect指令碼遠端登入
20.29 expect指令碼遠端執行命令
20.30 expect指令碼傳遞引數
20.27 分發系統介紹
公司的網站本來已經建好了,當公司的業務越來l越大時候就會需要實時更新程式碼,由於後端伺服器有很多臺來跑web服務。此時為了快速更新程式碼就可以使用分發系統。其中開源的上線程式碼的軟體有很多,git等等。這裡我們使用shell來編寫一個分發系統來上線程式碼。核心使用expect指令碼語言,它可以實現遠端執行命令,遠端傳輸資料等操作。
- 準備工作
1.準備1臺模版機器,裡面是包含有最新的程式碼
2.每臺分發機器的IP地址和密碼
3.分發系統指令碼
由於分發系統的核心是使用expect,因此先實踐幾個例子來熟悉expect的語法命令
20.28 expect指令碼遠端登入
例項1.自動遠端登入
expect指令碼機器 kun05 192.168.80.104
被遠端的機器 kun03 192.168.80.102
1.安裝expect語言
1 |
[[email protected] ~]# yum install -y expect |
2.編輯指令碼
1 2 |
[[email protected] ~]# cd /usr/local/sbin/ [[email protected] sbin]# vim expect1.exp |
寫入下面程式碼
1 2 3 4 5 6 7 8 9 10 11 12 |
#!/usr/bin/expect #定義變數 set host "192.168.80.102" set passwd "coco0769" #執行命令 spawn ssh [email protected]$host #與遠端機器互動 擷取特定資訊 傳送變數 expect { "yes/no" { send "yes\r";exp_continue } "password:" { send "$passwd\r" } } interact |
set
定義變數spawn
執行命令expect
使用expect語句進行互動\r
表示回車exp_contunue
表示繼續interact
表示繼續互動expect eof
表示停留遠端機器上一會兒再退出
為了讓遠端登入時候出現提示,可以清空/root/.ssh/known_hosts
目錄
1 |
[[email protected] ~]# > /root/.ssh/known_hosts |
測試
1.新增執行許可權
1 |
[[email protected] sbin]# chmod a+x expect1.exp |
2.執行指令碼
1 2 3 4 5 6 7 8 9 10 |
[[email protected] sbin]# ./expect1.exp spawn ssh [email protected] The authenticity of host '192.168.80.102 (192.168.80.102)' can't be established. ECDSA key fingerprint is SHA256:4QK/8Tn8lZAitB2+3wJMBuONgHExXkOAzZpYPndYoPQ. ECDSA key fingerprint is MD5:89:d5:7c:90:ff:d2:c6:1a:6e:f8:58:48:29:78:9a:f3. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.80.102' (ECDSA) to the list of known hosts. [email protected]'s password: Last login: Thu Jul 19 21:52:22 2018 from 192.168.80.104 [[email protected] ~]# |
已經成功登入kun03機器上
20.29 expect指令碼遠端執行命令
例項2.自動遠端登入,並執行命令並退出
編輯指令碼
1 |
[[email protected] sbin]# vim expect2.exp |
寫入下面程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#!/usr/bin/expect set user "root" set host "192.168.80.102" set passwd "coco0769" spawn ssh [email protected]$host expect { "yes/no" {send "yes\r";exp_continue} "password:" {send "$passwd\r"} } expect "]*" send "touch /tmp/test.aa\r" expect "]*" send "echo 111 >/tmp/test.aa\r" expect "]*" send "exit\r" |
測試
新增執行許可權並執行指令碼
1 2 3 4 5 6 7 |
[[email protected] sbin]# chmod a+x expect2.exp [[email protected] sbin]# ./expect2.exp spawn ssh [email protected] [email protected]'s password: Last login: Thu Jul 19 22:48:29 2018 from 192.168.80.104 [[email protected] ~]# touch /tmp/test.aa [[email protected] ~]# echo 111 >/tmp/test.aa |
進入kun03機器看看
1 2 3 4 |
[[email protected] ~]# ll /tmp/test.aa -rw-r--r-- 1 root root 4 7月 19 22:50 /tmp/test.aa [[email protected] ~]# cat /tmp/test.aa 111 |
20.28 expect指令碼傳遞引數
例項3.遠端傳遞引數
編輯指令碼
1 |
[[email protected] sbin]# vim expect3.exp |
寫入下面程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/usr/bin/expect set user [lindex $argv 0] set host [lindex $argv 1] set passwd "coco0769" set cmd [lindex $argv 2] spawn ssh [email protected]$host expect { "yes/no" {send "yes\r"} "password:" {send "$passwd\r"} } expect "]*" send "$cmd\r" expect "]*" send "exit\r" |
[lindex $argv 0]
表示要輸入的第一個引數 如此類推
測試
新增執行許可權並執行指令碼
1 2 3 4 5 6 7 8 9 10 11 12 |
[[email protected] sbin]# chmod a+x expect3.exp [[email protected] sbin]# ./expect3.exp root 192.168.80.102 "ls;w" spawn ssh [email protected] [email protected]'s password: Last login: Thu Jul 19 22:52:09 2018 from 192.168.80.1 [[email protected] ~]# ls;w anaconda-ks.cfg ip_forwarx~ ip_forwarz~ logs temp ip_forward~ ip_forwary~ log sim.pid zabbix-release-3.4-2.el7.noarch.rpm 23:45:34 up 2:02, 2 users, load average: 0.01, 0.03, 0.05 USER TTY FROM [email protected] IDLE JCPU PCPU WHAT root pts/0 192.168.80.1 22:52 7:58 0.01s 0.01s -bash root pts/1 192.168.80.104 23:45 0.00s 0.00s 0.00s w |
當要輸入引數裡面有多個命令是需要用""
雙引號括起來並使用;
分號分開
可以在命令列的後面增加set timeout
來指定命令的超時時間 -1
為永遠
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#!/usr/bin/expect set user [lindex $argv 0] set host [lindex $argv 1] set passwd "coco0769" set cmd [lindex $argv 2] spawn ssh [email protected]$host expect { "yes/no" {send "yes\r"} "password:" {send "$passwd\r"} } expect "]*" send "$cmd\r" set timeout -1 expect "]*" send "exit\r" |
測試
輸入vmstat命令
1 2 3 4 5 6 7 8 9 10 11 12 |
[[email protected] ~]# [[email protected] sbin]# ./expect3.exp "root" 192.168.80.102 "vmstat 1" spawn ssh [email protected] [email protected]'s password: Last login: Fri Jul 20 21:42:43 2018 from 192.168.80.104 [[email protected] ~]# vmstat 1 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 2 0 0 167852 2108 168580 0 0 35 3 85 113 0 0 99 0 0 0 0 0 167480 2108 168592 0 0 0 0 91 113 0 1 99 0 0 0 0 0 167480 2108 168592 0 0 0 0 104 119 0 0 100 0 0 0 0 0 167480 2108 168592 0 0 0 0 79 96 0 1 99 0 0 0 0 0 167480 2108 168592 0 0 0 0 89 106 0 0 100 0 0 |
現在是不斷地執行vmstat命令
20.31 expect指令碼同步檔案
20.32 expect指令碼指定host和要同步的檔案
20.33 構建檔案分發系統
20.34 批量遠端執行命令
20.31 expect指令碼同步檔案
例項4.自動同步檔案
編輯指令碼
1 |
[[email protected] sbin]# vim expect4.exp |
寫入下面程式碼
1 2 3 4 5 6 7 8 |
#!/usr/bin/expect set passwd "coco0769" spawn rsync -av [email protected]:/tmp/test.aa /tmp/ expect { "yes/no" {send "yes\r"} "password:" {send "$passwd\r"} } expect eof |
測試
新增執行許可權並執行指令碼
1 2 3 4 5 6 7 8 9 10 11 12 |
[[email protected] sbin]# chmod a+x expect4.exp [[email protected] sbin]# ./expect4.exp spawn rsync -av [email protected]:/tmp/test.aa /tmp/ [email protected]'s password: receiving incremental file list test.aa sent 43 bytes received 97 bytes 280.00 bytes/sec total size is 4 speedup is 0.03 [[email protected] sbin]# ll /tmp/test.aa -rw-r--r-- 1 root root 4 7月 19 22:50 /tmp/test.aa |
已經把192.168.80.102的test.aa檔案自動同步過來本機了
20.32 expect指令碼指定host和要同步的檔案
例項5.指定host和同步單個檔案
編輯指令碼
1 |
[[email protected] sbin]# vim expect5.exp |
寫入下面程式碼
1 2 3 4 5 6 7 8 9 10 |
#!/usr/bin/expect set passwd "coco0769" set host [lindex $argv 0] set file [lindex $argv 1] spawn rsync -av $file [email protected]$host:$file expect { "yes/no" {send "yes\r"} "password:" {send "$passwd\r"} } expect eof |
測試
新增執行許可權並執行指令碼
1 2 3 4 5 6 7 8 9 |
[[email protected] sbin]# chmod a+x expect5.exp [[email protected] sbin]# ./expect5.exp 192.168.80.102 /tmp/test spawn rsync -av /tmp/test [email protected]:/tmp/test [email protected]'s password: sending incremental file list test sent 85 bytes received 35 bytes 240.00 bytes/sec total size is 0 speedup is 0.00 |
20.33 構建檔案分發系統
分發系統中首先用expect編寫遠端同步指令碼
並指定檔案列表
和目標IP列表
然後使用shell指令碼
呼叫expect來同步檔案。
這裡每臺機器必須使用同樣的密碼才可以同步,也可以讓機器之前使用金鑰
登入。還有讓每臺機器都安裝上rsync
其核心命令為rsync -av --files-from=list.txt / [email protected]:/
1.編輯expect指令碼
1 |
[[email protected] sbin]# vim rsync.exp |
寫入下面程式碼
1 2 3 4 5 6 7 8 9 10 11 |
#!/usr/bin/expect set passwd "coco0769" set host [lindex $argv 0] set file [lindex $argv 1] #--file-from指定檔案列表路徑 -R表示同步時目標會級聯建立目錄 spawn rsync -avR --files-from=$file / [email protected]$host:/ expect { "yes/no" {send "yes\r"} "password:" {send $passwd\r} } expect eof |
2.建立ip.list 同步機器的IP列表
1 2 3 4 |
[[email protected] sbin]# vim /tmp/ip.list 192.168.80.102 192.168.80.103 |
3.建立file.list 需要同步檔案的列表
1 2 3 4 |
[[email protected] sbin]# vim /tmp/file.list /tmp/test /tmp/test.aa |
4.建立 rsync.sh 指令碼
1 |
[[email protected] sbin]# vim rsync.sh |
寫入下面程式碼
1 2 3 4 5 |
#!/bin/bash for i in `cat /tmp/ip.list` do ./rsync.exp $i /tmp/file.list done |
測試
新增執行許可權並執行指令碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
[[email protected] sbin]# chmod a+x rsync.exp [[email protected] sbin]# sh +x rsync.sh spawn rsync -avR --files-from=/tmp/file.list / [email protected]:/ [email protected]'s password: building file list ... done tmp/ tmp/test tmp/test.aa sent 185 bytes received 57 bytes 161.33 bytes/sec total size is 11 speedup is 0.05 spawn rsync -avR --files-from=/tmp/file.list / [email protected]:/ [email protected]'s password: building file list ... done tmp/ tmp/test tmp/test.aa sent 185 bytes received 57 bytes 484.00 bytes/sec total size is 11 speedup is 0.05 |
20.34 批量遠端執行命令
當同步完程式碼後有可能需要批量地重啟服務,因此還需要批量遠端執行命令,類似於自動化。
這裡是用expect編寫執行命令的指令碼並用shell指令碼來批量呼叫它。
1.編輯expect指令碼
1 |
[[email protected] sbin]# vim exe.exp |
寫入下面程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#!/usr/bin/expect set passwd "coco0769" set host [lindex $argv 0] set cmd [lindex $argv 1] spawn ssh [email protected]$host expect { "yes/no" {send "yes\r"} "password:" {send "$passwd\r"} } expect "]*" send "$cmd\r" expect "]*" send "exit\r" |
2.編寫shell指令碼
1 |
[[email protected] sbin]# vim exe.sh |
寫入下面程式碼
1 2 3 4 5 6 |
#!/bin/bash for i in `cat /tmp/ip.list` do echo $i ./exe.exp $i "service nginx restart" done |
測試
新增執行許可權並執行指令碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[[email protected] sbin]# chmod a+x exe.exp [[email protected] sbin]# sh exe.sh 192.168.80.102 spawn ssh [email protected] [email protected]'s password: Last login: Fri Jul 20 23:40:28 2018 from 192.168.80.104 [[email protected] ~]# service nginx restart Restarting nginx (via systemctl): [ 確定 ] 192.168.80.103 spawn ssh [email protected] [email protected]'s password: Last login: Fri Jul 20 23:38:46 2018 from 192.168.80.104 [[email protected] ~]# service nginx restart Restarting nginx (via systemctl): [ 確定 ] |
這裡kun03和kun04機器都執行了service nginx restart
命令