1. 程式人生 > >第二十章 Shell程式設計(下)

第二十章 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命令