shell指令碼案例

三思博客發表於2024-04-06

shell指令碼案例

1.伺服器系統配置初始化

背景:新購買10臺伺服器並已安裝linux操作
需求:
1.設定時區並同步時間
2.禁用selinux
3.清空防火牆預設策略
4.歷史命令顯示操作時間
5.禁止root遠端登入
6.禁止定時任務傳送郵件
7.設定最大開啟檔案數
8.減少swap使用
9.系統核心引數最佳化
10.安裝系統效能分析工具及其他







#!/bin/bash
#設定市區並同步時間
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
if ! crontab -l |grep ntpdate &>/dev/null ; then
       (echo "* 1 * * * ntpdate tiime.windows.com >/dev/null 2>&1";crontab -l) |crontab
fi


#禁用selinux
sed -i '/SELINUX/{s/permissive/disabled/}' /etc/selinux/config

#關閉防火牆
if egrep "7.[0-9]" /etc/centos-release &>/dev/null; then
   systemctl stop firewalld
   systemctl disable firewalld
elif egrep "6.[0-9]" /etc/centos-release &>/dev/null; then
   service iptables stop
   chkconfig iptables off
fi


#歷史命令現實操作時間
if ! grep HISTTIMEFORMAT /etc/bashrc; then
     echo 'export HISTTIMEFORMAT="%F %T whoami "' >> /etc/bashrc
fi


#ssh超時時間
if ! grep "TMOUT=600" /etc/profile &>/dev/null; then
     echo "export TMOUT=600" >> /etc/profile
fi

#禁止root遠端登入(一定要注意:這裡你需要還有一個賬戶,像root許可權的賬戶一樣,不然這裡改了,就沒root什麼事了)
sed -i 's/#PermitRootLogin yes/PermitROOTLogin no/' /etc/ssh/sshd_config



#禁止定時任務向傳送郵件
sed -i 's/^MAILTO=root/MAILTO=""/' /etc/crontab

#設定最大開啟檔案數
if ! grep "* soft nofile 65535" /etc/security/limits.conf &>/dev/null; then
     cat >> /etc/security/limits.conf << EOF
     * soft nofile 65535
     * hard nofile 65535
EOF
fi


#  系統核心最佳化
cat >> /etc/sysctl.conf << EOF
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_tw_buckes = 20480
net.ipv4.tcp_max_syn_backlog = 20480
net.core.netdev_max_backlog = 262144
net.ipv4.tcp_fin_timeout = 20
EOF

#減少swap使用
echo "0" > /proc/sys/vm/swappiness

#安裝系統效能分析工具及其他
yum install gcc make autoconf vim sysstat net-tools iostat iftop iotp lrzsz -y


指令碼註解--詳細版


這段指令碼是一段Linux Shell指令碼,主要用於初始化或配置Linux伺服器環境,主要涉及以下幾個方面:

1. 設定時區:將系統的時區設定為中國上海時間,確保系統時間與北京時間一致。

shell
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime


2. 定時同步時間:
   - 檢查當前crontab任務列表中是否存在ntpdate定時同步命令。
   - 如果不存在,新增一個新的cron任務,每天凌晨1點執行ntpdate命令從time.windows.com同步時間,並將標準輸出和錯誤輸出重定向至/dev/null忽略。

shell
if ! crontab -l | grep ntpdate &>/dev/null ; then
    (echo "* 1 * * * ntpdate time.windows.com >/dev/null 2>&1"; crontab -l) | crontab
fi


3. 禁用SELinux:修改SELinux配置檔案,將其模式從“寬容”更改為“禁用”,這樣在重啟後SELinux將不會對系統進行安全增強控制。

shell
sed -i '/SELINUX/{s/permissive/disabled/}' /etc/selinux/config


4. 關閉防火牆:
   - 針對CentOS 7.x版本及更高版本,停止firewalld服務並禁止其開機啟動。
   - 對於CentOS 6.x版本,停止iptables服務並設定其開機不啟動。

shell
if egrep "7.[0-9]" /etc/centos-release &>/dev/null; then
   systemctl stop firewalld
   systemctl disable firewalld
elif egrep "6.[0-9]" /etc/centos-release &>/dev/null; then
   service iptables stop
   chkconfig iptables off
fi


5. 顯示命令執行時間:檢查並修改/etc/bashrc檔案,以便在顯示命令歷史記錄時包含每條命令的執行時間戳。

shell
if ! grep HISTTIMEFORMAT /etc/bashrc; then
     echo 'export HISTTIMEFORMAT="%F %T whoami "' >> /etc/bashrc
fi


6. 設定SSH超時時間:若/etc/profile檔案中未設定SSH會話超時時間(600秒,即10分鐘),則追加此設定,以防止長時間無操作導致的空閒會話持續佔用資源。

shell
if ! grep "TMOUT=600" /etc/profile &>/dev/null; then
     echo "export TMOUT=600" >> /etc/profile
fi


總之,這段指令碼透過一系列命令來調整伺服器的基本配置,包括時區設定、時間同步、安全策略、網路防護以及互動式終端的超時管理等。這些設定有助於最佳化伺服器效能和安全性,同時也方便了日常運維工作。

2.傳送告警郵件

1.外部郵箱伺服器   163

 yum -y install postfix  
 yum install mailx -y
 systemctl stop firewalld
 getenforce 0
 
 vi /etc/mail.rc
et from=15178374440@163.com
set smtp=smtp.163.com
set smtp-auth-user=15178374440@163.com
set smtp-auth-password=PSOHJFUPVIXBZSBD
set smtp-auth=login


echo "系統有異常問題,請檢查系統" |mail -s "異常警告" 15178374440@163.com
echo "nginx服務掛了" | mailx -s "預警" 15178374440@163.com







--------------------------------------------------------
#tips:提示--如果出現這種情況   
[root@centos7mage scripts]# smtp-server: 553 authentication is required,163 gzga-smtp-mta-g1-5,_____wDXbzGsvBBmi53wAA--.14211S2 1712372918
"/root/dead.letter" 11/313
. . . message not sent.
^C



解決:還是 /etc/mail.rc 這個配置檔案裡面之前的配置不正確,一定要格式配置正確,不能少字母


3.批次建立100個使用者和密碼




#!/bin/bash
USER_LIST=$@
USER_FILE=./user.info
for USER in $USER_LIST; do
   if ! id $USER &>/dev/null; then
    PASS=$(echo $RONDOM |md5sum |cut -c 1-8)
    useradd $USER
    echo $PASS | passwd --stdin $USER &>/dev/null
    echo "$USER   $PASS"  >> $USER_FILE
    echo "$USER User create successful."
   else
     echo "$USER User already exists!"

   fi

done




指令碼註解
這是一個bash指令碼,用於根據提供的使用者列表建立新使用者,併為每個新使用者生成隨機密碼。具體執行過程如下:

1. 指令碼首先透過$@獲取命令列傳入的所有引數作為待建立的使用者列表(USER_LIST)。

2. 然後設定一個檔案路徑變數USER_FILE,其值為"./user.info",這個檔案將用來儲存新建立使用者的使用者名稱和密碼資訊。

3. 使用for迴圈遍歷USER_LIST中的每一個使用者(USER)。

4. 在迴圈內,使用id $USER &>/dev/null命令檢查當前使用者是否已存在。如果不存在(即命令返回非0狀態碼),則執行以下操作:
   - 生成一個隨機密碼:利用RANDOM變數生成隨機數,然後透過md5sum計算其MD5值,並擷取前8個字元作為密碼(PASS)。
   - 使用useradd命令建立新使用者($USER)。
   - 使用passwd命令設定新使用者的密碼(透過管道將密碼作為輸入傳遞給--stdin選項)。
   - 將使用者名稱($USER)和密碼($PASS)寫入到$USER_FILE檔案中。
   - 輸出提示資訊告知使用者建立成功。

5. 如果當前使用者已經存在,則輸出提示資訊告知該使用者已存在。

總的來說,這個指令碼是用來批次建立系統使用者並記錄下對應使用者名稱和隨機密碼的實用工具。

4.一鍵檢視伺服器利用率

1.CPU  60%      top vmstat
2.記憶體  利用率     free -m
3.硬體  利用率     df -h
4.TCP連線狀態     ss -tulpn netstat-tulpn




#!/bin/bash
function cpu(){
     
  util=$(vmstat |awk '{if(NR==3)print $13+$14}')
  iowait=$(vmstat |awk '{if(NR==3)print $16}')
  echo "CPU - 使用率: ${util}% , 等待磁碟IO響應使用率: ${iowait}%"
}
function memory(){
  total=$(free -m |awk '{if(NR==2)printf "%.1f", $2/1024}')
  used=$(free -m |awk '{if(NR==2)printf "%.1f",($2-$NF)/1024}')
  available=$(free -m |awk '{if(NR==2)printf "%.1f",$NF/1024}')
  echo "記憶體 - 總大小: ${total}G , 已使用:${user}G , 剩餘: ${available}G"
}
disk(){
    fs=$(df -h |awk '/^\/dev/{print $1}')
    for p in $fs; do
    mounted=$(df -h |awk -v p=$p '$1==p{print $NF}')
    size=$(df -h |awk -v p=#p '$1==p{print $2}')
    used=$(df -h |awk -v p=#p '$1==p{print $3}')
    user_percent=$(df -h |awk -v p=$p '$1==p{print $5}')
    echo "硬碟 - 掛載點: $mounted , 總大小: $size , 已使用: $used , 使用率:$user_percent"
done
}
tcp_status(){
    summary=$(netstat -antp | awk '{a[$6]++} END{for(i in a) print i ": " a[i] " "}')
    echo  "TCP連線狀態 - $summary "
}
cpu
memory
disk
tcp_status





指令碼註釋




這段指令碼定義了四個函式,用於顯示系統資源狀態:

1. cpu()函式:獲取CPU使用率和等待磁碟I/O響應的使用率,並顯示結果。

2. memory()函式:計算並顯示記憶體總量、已使用量和剩餘可用量(單位為GB)。

3. disk()函式:迴圈遍歷所有硬碟分割槽,顯示每個分割槽的掛載點、總大小、已使用量及使用率。

4. tcp_status()函式:統計並顯示系統中各種TCP連線狀態的數量。

執行指令碼會依次輸出CPU、記憶體、硬碟各分割槽以及TCP連線狀態的資訊。


tcp_status()函式的作用是從系統中收集並彙總TCP連線的不同狀態,然後輸出統計結果。

以下是該函式的具體步驟:

1. 執行命令 netstat -antp 來獲取當前系統中所有的網路連線資訊,包括TCP連線的狀態、本地和遠端地址、埠號以及程序PID等。

2. 透過管道 | 把netstat命令的輸出傳遞給awk命令進行處理。

   bash
   summary=$(netstat -antp | awk '{a[$6]++} END{for(i in a) print i ": " a[i] " "}')
   

   在awk指令碼中:
   - {a[$6]++} 表示將每行中的第6列(TCP連線狀態)作為鍵值存入關聯陣列a中,並將對應狀態的計數加1,這樣就實現了對不同狀態的連線數目的統計。
   
   - END{for(i in a) print i ": " a[i] " "} 在處理完所有行後,遍歷陣列a,列印出每種TCP連線狀態及其出現的次數,格式為"狀態: 數量 "。

3. 最終,統計結果會被賦值給變數summary。

4. 當呼叫tcp_status函式時,它會執行上述操作,並輸出類似下面的結果:
   
   ESTABLISHED: 10
   LISTEN: 5
   TIME_WAIT: 3
   ...
   
   這意味著系統中有10個處於"ESTABLISHED"狀態的TCP連線,5個處於"LISTEN"狀態的連線,3個處於"TIME_WAIT"狀態的連線等等。
   
   
   

5.找出佔用cpu/記憶體過高的程序



#!/bin/bash
echo "--------------------------- cpu top 10  ----------------------"
ps -eo pid,pcpu,pmem,args --sort=-pcpu |head -n 10
echo "--------------------------- memroy top 10  ----------------------"
ps -eo pid,pcpu,pmem,args --sort=-pmem |head -n 10
echo "--------------------------- cpu top 10  ----------------------"
ps -eo pid,pcpu,pmem,args --sort=-args |head -n 10







指令碼註釋
這段bash指令碼用於展示系統中佔用CPU、記憶體資源最多的前10個程序的相關資訊。

1. echo "--------------------------- cpu top 10  ----------------------"
   這一行會輸出一個分隔符,表示接下來要顯示的是CPU使用率最高的前10個程序。

2. ps -eo pid,pcpu,pmem,args --sort=-pcpu | head -n 10
   使用ps命令查詢系統中所有程序的詳細資訊,引數說明如下:
   - -e:顯示所有程序(包括其他使用者的)。
   - -o:指定輸出格式,這裡選擇了pid(程序ID)、pcpu(CPU使用百分比)、pmem(記憶體使用百分比)和args(命令列引數)這四項資訊。
   - --sort=-pcpu:按CPU使用率降序排序(最高優先顯示)。
   - | head -n 10:將排序後的輸出結果透過管道傳遞給head命令,僅顯示前10條資料。

3. 同理,第二個echo和ps命令組合用於輸出記憶體使用率最高的前10個程序。

4. 第三個echo和ps命令組合理論上應該也是用於輸出某種排序後的程序資訊,但是這裡的--sort=-args實際上是按命令列引數字串長度降序排序,所以可能並非展示CPU佔用情況。通常情況下,我們並不會按照命令列引數來排序程序,這段程式碼可能存在誤寫。如果目的是檢視CPU佔用排名,應重複第一個ps命令;如果是想看命令列最長的程序,則無需在標題中再次寫"cpu top 10"。

6.檢視網路卡實施流量

#!/bin/bash
NIC=$1

# 初始化變數
OLD_IN=0
OLD_OUT=0

echo -e "In\t--------\tOut"

while true; do
    # 獲取舊的流入和流出資料量
    OLD_IN=$(awk -v nic="$NIC" '$0~nic{print $2}' /proc/net/dev)
    OLD_OUT=$(awk -v nic="$NIC" '$0~nic{print $10}' /proc/net/dev)

    # 等待1秒
    sleep 1
    
    # 獲取新的流入和流出資料量
    NET_IN=$(awk -F'[: ]+' -v nic="$NIC" '$0~nic{print $2}' /proc/net/dev)
    NET_OUT=$(awk -F'[: ]+' -v nic="$NIC" '$0~nic{print $10}' /proc/net/dev)

    # 計算流量差值並格式化輸出
    IN=$(printf "%.1f%s" "$(( ($NET_IN - $OLD_IN) / 1024 ))" "KB/s")
    OUT=$(printf "%.1f%s" "$(( ($NET_OUT - $OLD_OUT) / 1024 ))" "KB/s")

    # 輸出結果
    echo "$IN\t$OUT"

    # 更新舊的流入和流出資料量
    OLD_IN=$NET_IN
    OLD_OUT=$NET_OUT
done




執行演示
[root@centos7mage scripts]# sh 5.sh eth0
In	--------	Out
-200397.0KB/s\t-4627.0KB/s
-200397.0KB/s\t-4627.0KB/s
-200397.0KB/s\t-4627.0KB/s
-200397.0KB/s\t-4628.0KB/s
-200397.0KB/s\t-4628.0KB/s
-200398.0KB/s\t-4628.0KB/s
-200398.0KB/s\t-4628.0KB/s
-200398.0KB/s\t-4628.0KB/s
-200398.0KB/s\t-4629.0KB/s
-200398.0KB/s\t-4629.0KB/s
-204153.0KB/s\t-4683.0KB/s
-210496.0KB/s\t-4773.0KB/s
-210497.0KB/s\t-4774.0KB/s
-210497.0KB/s\t-4774.0KB/s
-210497.0KB/s\t-4774.0KB/s
-210497.0KB/s\t-4774.0KB/s

指令碼註釋

當然,很高興為您逐模組解釋這個bash指令碼:

1. 引數接受與變數初始化
   - NIC=$1:指令碼接收命令列的第一個引數作為要監控的網路卡名稱,儲存在變數NIC中。
   - 初始化兩個變數OLD_IN和OLD_OUT,它們分別用來暫存上次採集到的流入和流出網路流量。

2. 輸出表格標題
   - echo -e "In\t--------\tOut":輸出表格標題,表示將展示流入(In)和流出(Out)的網路流量對比。

3. 迴圈獲取與展示流量資料
   - 獲取舊的流入和流出資料量:
     - 使用awk命令查詢與NIC變數匹配的行,並獲取第二列(流入資料量)和第十列(流出資料量),分別賦值給OLD_IN和OLD_OUT。
   - 等待1秒:
     - sleep 1讓指令碼暫停1秒,等待下一次流量資料採集。
   - 獲取新的流入和流出資料量:
     - 同樣的方式獲取當前時刻的流入和流出資料量,儲存在NET_IN和NET_OUT中。
   - 計算流量差值並格式化輸出:
     - 計算新的流量值與舊的流量值之差,除以1024換算成KB/s,然後格式化輸出(保留一位小數)。
   - 輸出結果:
     - 使用echo命令輸出當前的流入和流出流量速率(KB/s)。
   - 更新舊的流入和流出資料量:
     - 將新的流量值賦給OLD_IN和OLD_OUT,準備下一輪迴圈的流量差值計算。

綜上所述,該指令碼是一個持續監控指定網路卡流量的迴圈程式,每秒輸出一次流入和流出的網路流量速率。

7.批次檢查網站是否正常

ssh-keygen
ls .ssh/
ssh-copy-id root@10.0.0.1


vim host.info
10.0.1.143 root 22
10.0.1.142 root 22



#!/bin/bash
HOST_INFO="host.info"
for IP in $(awk '/^[^#]/{print $1}' "$HOST_INFO"); do
    USER=$(awk -v ip="$IP" '$1 == ip {print $2}' "$HOST_INFO")
    PORT=$(awk -v ip="$IP" '$1 == ip {print $3}' "$HOST_INFO")
    TMP_FILE=/tmp/disk.tmp
    ssh -p "$PORT" "$USER@$IP" 'df -h' > "$TMP_FILE"
    USER_RATE_LIST=$(awk 'BEGIN{OFS="="}/^\/dev/{print $NF,int($5)}' "$TMP_FILE")
    for USE_RATE in $USER_RATE_LIST; do
        PART_NAME=${USE_RATE%=*}
        USE_RATE=${USE_RATE#*=}
        if [ "$USE_RATE" -ge 80 ]; then
           echo "Warning: $PART_NAME Partition usage $USE_RATE%!"
        fi
     done
done








測試
sudo dd if=/dev/zero of=/tmp/fill_5GB bs=1G count=5


指令碼註釋
這段指令碼是一個Bash shell指令碼,用於透過SSH連線遠端主機並檢查各主機的磁碟使用率,當磁碟使用率達到或超過80%時發出警告。下面是該指令碼每部分功能的通俗解釋:

1. 定義變數和檔名:
   bash
   HOST_INFO="host.info"
   TMP_FILE=/tmp/disk.tmp
   
   - HOST_INFO 是一個包含主機資訊的檔案,每一行記錄了一個主機的IP地址、使用者名稱和埠號。
   - TMP_FILE 是臨時檔名,用來儲存從遠端主機上執行df -h命令得到的磁碟使用情況。

2. 迴圈讀取主機資訊:
   bash
   for IP in $(awk '/^[^#]/{print $1}' "$HOST_INFO")
   
   這個迴圈遍歷HOST_INFO檔案中的每一行非註釋行,並提取第一列(即IP地址)作為迴圈變數。

3. 獲取使用者和埠資訊:
   bash
   USER=$(awk -v ip="$IP" '$1 == ip {print $2}' "$HOST_INFO")
   PORT=$(awk -v ip="$IP" '$1 == ip {print $3}' "$HOST_INFO")
   
   對於每個IP地址,利用awk從HOST_INFO檔案中匹配出對應的使用者名稱(第二列)和埠號(第三列)。

4. 透過SSH連線遠端主機並獲取磁碟使用情況:
   bash
   ssh -p "$PORT" "$USER@$IP" 'df -h' > "$TMP_FILE"
   
   使用指定的使用者名稱、IP地址和埠號透過SSH登入到遠端主機,並執行df -h命令獲取磁碟使用情況,然後將結果輸出儲存到本地臨時檔案$TMP_FILE。

5. 解析磁碟使用率:
   bash
   USER_RATE_LIST=$(awk 'BEGIN{OFS="="}/^\/dev/{print $NF,int($5)}' "$TMP_FILE")
   
   從臨時檔案中提取以/dev/開頭的行(通常表示磁碟分割槽),並將最後一列(磁碟掛載點)與第五列(磁碟使用百分比,轉換為整數形式)之間用等號連線起來,形成如PARTITION_NAME=USAGE_PERCENT的列表。

6. 檢查並輸出警告:
   bash
   for USE_RATE in $USER_RATE_LIST; do
       PART_NAME=${USE_RATE%=*}
       USE_RATE=${USE_RATE#*=}
       if [ "$USE_RATE" -ge 80 ]; then
          echo "Warning: $PART_NAME Partition usage $USE_RATE%!"
       fi
   done
   
   再次迴圈遍歷處理後的磁碟使用率列表,從中分離出分割槽名和使用率。如果使用率大於等於80%,則輸出一條警告訊息,顯示分割槽名及其使用率百分比。

總之,此指令碼的主要目的是自動化地監控多個遠端伺服器的磁碟使用情況,並對磁碟使用率過高的情況進行警報。






8.批次自動化執行命令

[root@centos7mage scripts]# curl -o /de/dev/null -s -w "%{http_code}" http://www.baidu.com
200[root@centos7mage scripts]# 




#!/bin/bash
URL_LIST="www.baidu.com www.sansi.fun"
for URL in $URL_LIST; do
    FAIL_COUNT=0
    for ((i=1;i<=3;i++)); do
            HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%{http_code}" $URL)
      if  [ $HTTP_CODE -eq 200 ]; then
             echo "$URL OK"
          break
      else
         echo "$URL retry $FAIL_COUNT"
         let FAIL_COUNT++
      fi
     done
     if [ $FAIL_COUNT -eq 3 ]; then
          echo "Wraning: $URL Access failure!"
     fi
done





指令碼註釋

這段指令碼是一個簡單的Bash指令碼,其功能是對指定列表中的URL進行網頁訪問狀態檢查。具體解釋如下:

1. 首先,定義了一個字串變數URL_LIST,裡面包含了待檢查的網址列表,例如:"www.baidu.com" 和 "www.sansi.fun"。

2. 使用for迴圈遍歷URL_LIST中的每一個URL。

3. 初始化一個變數FAIL_COUNT,用於記錄嘗試訪問某個URL失敗的次數。

4. 對每個URL,執行一個內部的計數迴圈,最多嘗試3次訪問:

   - 使用curl命令嘗試訪問URL,其中-o /dev/null表示不輸出頁面內容,--connect-timeout 3表示連線超時時間為3秒,-s表示靜默模式,不輸出進度等資訊,-w "%{http_code}"表示只輸出HTTP響應碼。

   - 判斷返回的HTTP響應碼HTTP_CODE是否為200(代表請求成功)。若是200,則輸出"$URL OK"並跳出內層迴圈。

   - 若HTTP響應碼不是200,則輸出"$URL retry $FAIL_COUNT"(表示正在進行第幾次重試),並將FAIL_COUNT加1。

5. 當內層迴圈結束後(即嘗試了3次訪問之後),檢查FAIL_COUNT是否等於3,若是,則表示連續3次訪問都未能成功,此時輸出"Wraning: $URL Access failure!"(注意這裡的"Wraning"應該是"Warning"的拼寫錯誤)。

綜上所述,這個指令碼主要用於檢查給定列表中的網站URL是否能正常訪問,並在多次訪問失敗後發出警告。


9.批次主機執行命令

expect

需求:多臺機器 要求在一臺機器上執行命令,此命令也要同時在其他機器上執行

vim host.info
10.0.1.142 root 22 123456
10.0.1.143 root 22 123456

#tips:上面的格式可自己定義,不過要對應下面的指令碼檔案 


#!/bin/bash
COMMAND=$*
HOST_INFO=host.info
for IP in $(awk '/^[^#]/{print $1}' $HOST_INFO); do
       USER=$(awk -v ip=$IP 'ip==$1{print $2}' $HOST_INFO)
       PORT=$(awk -v ip=$IP 'ip==$1{print $3}' $HOST_INFO)
       PASS=$(awk -v ip=$IP 'ip==$1{print $4}' $HOST_INFO)
       expect -c "
         spawn ssh -p $PORT $USER@$IP
         expect {
          \"(yes/no)\" {send \"yes\r\"; exp_continue}
          \"password:\" {send \"$PASS\r\"; exp_continue}
          \"$USER@*\" {send \"$COMMAND\r exit\r\"; exp_continue}
}
"
echo "------------------------"
done



指令碼註釋

現在指令碼已修復,能夠正確從host.info檔案中提取IP地址、使用者名稱、SSH埠和密碼,並使用expect透過SSH登入遠端主機執行命令。host.info檔案格式為:IP 地址 使用者名稱 SSH埠 密碼。

不過,請注意,在生產環境中直接在指令碼中硬編碼密碼是非常不安全的做法,應考慮使用SSH金鑰對進行無密碼登入,或者透過安全方式傳遞密碼(例如環境變數或加密儲存並透過解密獲取)。

以下是修正後的指令碼解釋:

1. 獲取命令列傳入的引數,儲存在COMMAND變數中。
2. 設定HOST_INFO變數為包含主機資訊的檔名。
3. 遍歷HOST_INFO檔案中的每一行(非註釋行),提取IP地址。
4. 對於每個IP地址,分別提取對應的使用者名稱、SSH埠和密碼。
5. 使用expect指令碼透過SSH登入遠端主機:
   - 傳送yes回答關於未知主機金鑰的確認。
   - 輸入密碼進行身份驗證。
   - 登入成功後,傳送要執行的命令和退出命令($COMMAND和exit)。
6. 每次迴圈結束時,列印分割線以區分不同主機的執行結果。

10.一鍵部署LNM網站

LNMP
linux  nginx  mysql php

user -> nginx -> php -> mysql


centos
1.yum
2.原始碼安裝
./configure  
make 
make install
3.二進位制安裝



選單
1
2
3
4


#!/bin/bash
NGINX_V=1.15.6
PHP_V=5.6.36
TMP_DIR=/tmp

INSTALL_DIR=/usr/local

PWD_C=$PWD

echo
echo -e "\tMenu\n"
echo -e "1. Install Nginx"
echo -e "2. Install PHP"
echo -e "3. Install MySQL"
echo -e "4. Deploy LNMP"
echo -e "9. Quit"

function command_status_check() {
	if [ $? -ne 0 ]; then
		echo $1
		exit
	fi 
}

function install_nginx() {
    cd $TMP_DIR
    yum install -y gcc gcc-c++ make openssl-devel pcre-devel wget
    wget http://nginx.org/download/nginx-${NGINX_V}.tar.gz
    tar zxf nginx-${NGINX_V}.tar.gz
    cd nginx-${NGINX_V}
    ./configure --prefix=$INSTALL_DIR/nginx \
    --with-http_ssl_module \
    --with-http_stub_status_module \
    --with-stream
    command_status_check "Nginx - 平臺環境檢查失敗!"
    make -j 4 
    command_status_check "Nginx - 編譯失敗!"
    make install
    command_status_check "Nginx - 安裝失敗!"
    mkdir -p $INSTALL_DIR/nginx/conf/vhost
    alias cp=cp ; cp -rf $PWD_C/nginx.conf $INSTALL_DIR/nginx/conf
    rm -rf $INSTALL_DIR/nginx/html/*
    echo "ok" > $INSTALL_DIR/nginx/html/status.html
    echo '<?php echo "ok"?>' > $INSTALL_DIR/nginx/html/status.php
    $INSTALL_DIR/nginx/sbin/nginx
    command_status_check "Nginx - 啟動失敗!"
}

function install_php() {
	cd $TMP_DIR
    yum install -y gcc gcc-c++ make gd-devel libxml2-devel \
        libcurl-devel libjpeg-devel libpng-devel openssl-devel \
        libmcrypt-devel libxslt-devel libtidy-devel
    wget http://docs.php.net/distributions/php-${PHP_V}.tar.gz
    tar zxf php-${PHP_V}.tar.gz
    cd php-${PHP_V}
    ./configure --prefix=$INSTALL_DIR/php \
    --with-config-file-path=$INSTALL_DIR/php/etc \
    --enable-fpm --enable-opcache \
    --with-mysql --with-mysqli --with-pdo-mysql \
    --with-openssl --with-zlib --with-curl --with-gd \
    --with-jpeg-dir --with-png-dir --with-freetype-dir \
    --enable-mbstring --enable-hash
    command_status_check "PHP - 平臺環境檢查失敗!"
    make -j 4 
    command_status_check "PHP - 編譯失敗!"
    make install
    command_status_check "PHP - 安裝失敗!"
    cp php.ini-production $INSTALL_DIR/php/etc/php.ini
    cp sapi/fpm/php-fpm.conf $INSTALL_DIR/php/etc/php-fpm.conf
    cp sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm
    chmod +x /etc/init.d/php-fpm
    /etc/init.d/php-fpm start
    command_status_check "PHP - 啟動失敗!"
}

read -p "請輸入編號:" number
case $number in
    1)
        install_nginx;;
    2)
        install_php;;
    3)
        install_mysql;;
    4)
        install_nginx
        install_php
        ;;
    9)
        exit;;
esac






測試
ps aux|grep nginx
ps aux|grep mysql
ps aux |grep php


指令碼註釋
這個指令碼是一個用於在Linux環境下安裝LNMP(Nginx、PHP、MySQL)棧的Shell指令碼。它提供了選單選項供使用者選擇單獨安裝Nginx、PHP或MySQL,也可以選擇部署整個LNMP棧。

1. 安裝Nginx函式:
   - 進入臨時目錄,安裝依賴包如gcc、make等。
   - 下載指定版本的Nginx原始碼包並解壓。
   - 進入Nginx原始碼目錄並配置編譯選項,包括指定安裝目錄、啟用SSL模組、狀態模組和流模組。
   - 配置完成後進行編譯和安裝,並建立必要的配置資料夾和預設站點檔案。
   - 最後啟動Nginx服務並檢查啟動狀態。

2. 安裝PHP函式:
   - 同樣進入臨時目錄,安裝PHP所需的開發庫依賴。
   - 下載指定版本的PHP原始碼包並解壓。
   - 進入PHP原始碼目錄,配置編譯選項,包括指定安裝目錄、啟用PHP-FPM、OPCache,並連線MySQL資料庫支援等。
   - 配置完成後進行編譯和安裝,並複製配置檔案和啟動指令碼到相應位置。
   - 最後啟動PHP-FPM服務並檢查啟動狀態。

3. 指令碼中還有一個未定義的函式install_mysql,推測是用來安裝MySQL資料庫的,但具體內容未給出。

4. 指令碼最後根據使用者輸入的數字執行對應的功能,如果輸入的是4,則依次安裝Nginx和PHP。輸入9則退出指令碼。

在指令碼執行過程中,command_status_check函式用於檢查前面命令的執行狀態,如果狀態碼不為0(表示命令執行失敗),則輸出錯誤資訊並退出指令碼。

11.監控mysql主從狀態異常


change master to
master_host='192.168.10.130',
master_host='rep1',
master_password='password',
master_log_file='mysql-bin.000005',
master_log_pos=261;



主從同步
master binlog
slave

寫 -> master -> binlog <- relaylog -> slave




!/bin/bash  
HOST=localhost
USER=root
PASSWD=123.com
IO_SQL_STATUS=$(mysql -h$HOST -u$USER -p$PASSWD -e 'show slave status\G' 2>/dev/null |awk '/Slave_.*_Running:/{print $1$2}')
for i in $IO_SQL_STATUS; do
    THREAD_STATUS_NAME=${i%:*}
    THREAD_STATUS=${i#*:}
    if [ "$THREAD_STATUS" != "Yes" ]; then
        echo "Error: MySQL Master-Slave $THREAD_STATUS_NAME status is $THREAD_STATUS!" |mail -s "Master-Slave Staus" xxx@163.com
    fi
done




指令碼註釋

此指令碼是一個用於檢查MySQL主從複製狀態的bash指令碼。它連線到本地MySQL伺服器(localhost),以root使用者身份登入(密碼為123.com),執行SQL命令 show slave status\G 來獲取主從複製的狀態資訊。

透過管道將SQL命令的結果傳給awk命令,awk命令查詢含有'Slave_'開始且後面緊跟'_Running:'的行,並列印這部分資訊(即狀態名和狀態值)。

接著,透過for迴圈迭代awk命令輸出的每一項,將狀態名和狀態值分別賦值給變數THREAD_STATUS_NAME和THREAD_STATUS。

迴圈體內的if條件判斷,如果THREAD_STATUS的值不是"Yes"(意味著從庫執行緒沒有在執行),就將錯誤資訊透過郵件命令傳送給指定郵箱(xxx@163.com),主題是"Master-Slave Staus"。

總結來說,這個指令碼是為了監控MySQL主從複製的執行狀態,當發現任何一個複製執行緒沒有正常執行時,就會向指定郵箱傳送報警郵件。

12.mysql 資料備份

mysqldump
分庫
分表


mysqldump -uroot -pxxx -B -A >/home/a.sql  備份庫
mysqldump -uroot -pxxx A t > /home/a.sql 備份表



單迴圈
!/bin/bash
DATE=$(date +%F_%H-%M-%S)
HOST=localhost
USER=backup
PASS=123.com
BACKUP_DIR=/data/db_backup
DB_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "show databases;" 2>/dev/null |egrep -v "Database|information_schema|mysql|performance_schema|sys")

for DB in $DB_LIST; do
    BACKUP_NAME=$BACKUP_DIR/${DB}_${DATE}.sql
    if ! mysqldump -h$HOST -u$USER -p$PASS -B $DB > $BACKUP_NAME 2>/dev/null; then
        echo "$BACKUP_NAME 備份失敗!"
    fi
done




多迴圈
#!/bin/bash
DATE=$(date +%F_%H-%M-%S)
HOST=localhost
USER=backup
PASS=123.com
BACKUP_DIR=/data/db_backup
DB_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "show databases;" 2>/dev/null |egrep -v "Database|information_schema|mysql|performance_schema|sys")

for DB in $DB_LIST; do
    BACKUP_DB_DIR=$BACKUP_DIR/${DB}_${DATE}
    [ ! -d $BACKUP_DB_DIR ] && mkdir -p $BACKUP_DB_DIR &>/dev/null
    TABLE_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "use $DB;show tables;" 2>/dev/null)
    for TABLE in $TABLE_LIST; do
        BACKUP_NAME=$BACKUP_DB_DIR/${TABLE}.sql 
        if ! mysqldump -h$HOST -u$USER -p$PASS $DB $TABLE > $BACKUP_NAME 2>/dev/null; then
            echo "$BACKUP_NAME 備份失敗!"
        fi
    done
done


指令碼註釋

13.nginx日誌分析指令碼

1.訪問最多的ip
2.訪問最多的頁面
3.訪問頁面狀態碼數量
4.根據時間段來訪問最多的IP

UV 使用者訪問次數 (天)
PV 總頁面訪問次數 (天)



#!/bin/bash
# 日誌格式: $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"
LOG_FILE=$1
echo "統計訪問最多的10個IP"
awk '{a[$1]++}END{print "UV:",length(a);for(v in a)print v,a[v]}' $LOG_FILE |sort -k2 -nr |head -10
echo "----------------------"

echo "統計時間段訪問最多的IP"
awk '$4>="[01/Dec/2018:13:20:25" && $4<="[27/Nov/2018:16:20:49"{a[$1]++}END{for(v in a)print v,a[v]}' $LOG_FILE |sort -k2 -nr|head -10
echo "----------------------"

echo "統計訪問最多的10個頁面"
awk '{a[$7]++}END{print "PV:",length(a);for(v in a){if(a[v]>10)print v,a[v]}}' $LOG_FILE |sort -k2 -nr
echo "----------------------"

echo "統計訪問頁面狀態碼數量"
awk '{a[$7" "$9]++}END{for(v in a){if(a[v]>5)print v,a[v]}}' $LOG_FILE |sort -k3 -nr







測試
[root@centos7mage scripts]# sh 13.sh /usr/local/nginx/logs/access.log
統計訪問最多的10個IP
10.0.1.1 466
UV: 1
----------------------
統計時間段訪問最多的IP
10.0.1.1 466
----------------------
統計訪問最多的10個頁面
/ 464
PV: 2
----------------------
統計訪問頁面狀態碼數量
/ 304 426
/ 403 21
/ 200 17

指令碼註解

14.nginx日誌自動切割











#!/bin/bash
LOG_DIR=/usr/local/nginx/logs
YESTERDAY_TIME=$(date -d "yesterday" +%F)
LOG_MONTH_DIR=$LOG_DIR/$(date +"%Y-%m")
LOG_FILE_LIST="default.access.log"

for LOG_FILE in $LOG_FILE_LIST; do
    [ ! -d $LOG_MONTH_DIR ] && mkdir -p $LOG_MONTH_DIR
    mv $LOG_DIR/$LOG_FILE $LOG_MONTH_DIR/${LOG_FILE}_${YESTERDAY_TIME}
done

kill -USR1 $(cat /var/run/nginx.pid)

指令碼註釋
這段指令碼是一個簡單的bash指令碼,用於管理和歸檔Nginx的日誌檔案。下面是指令碼的詳細解釋:

1. 首先,定義了日誌目錄LOG_DIR為 /usr/local/nginx/logs,這是Nginx存放日誌的預設路徑。

2. 計算昨天的日期,並將其賦值給變數YESTERDAY_TIME,格式為 %F,即年-月-日。

3. 建立一個變數LOG_MONTH_DIR,它的值是LOG_DIR目錄下對應當前月份的子目錄,格式為%Y-%m。

4. 設定一個變數LOG_FILE_LIST,在這裡只包含一個固定的日誌檔名default.access.log。

5. 使用for迴圈遍歷LOG_FILE_LIST中列出的日誌檔名。

6. 在迴圈體內,首先檢查LOG_MONTH_DIR是否存在,如果不存在則建立該目錄及其所有上級目錄(mkdir -p命令的作用)。

7. 將LOG_DIR下的當前日誌檔案移動到昨天的日期命名的檔案中,儲存在LOG_MONTH_DIR目錄下。

8. 迴圈結束後,向Nginx主程序傳送USR1訊號,該訊號會導致Nginx重新開啟其日誌檔案。這裡透過讀取/var/run/nginx.pid檔案獲取Nginx主程序ID,並向其傳送訊號。

總之,這個指令碼的主要作用是每天將前一天的Nginx訪問日誌移動到按月分類的目錄下,並重新開啟日誌檔案以便繼續記錄今天的日誌。

15.自動釋出java專案

程式碼已經提交到版本倉庫,執行shell指令碼一鍵部署

java -> jar/war ->tomcat/resin jar -jar



#!/bin/bash
DATE=$(date +%F_%T)

TOMCAT_NAME=$1
TOMCAT_DIR=/usr/local/$TOMCAT_NAME
ROOT=$TOMCAT_DIR/webapps/ROOT

BACKUP_DIR=/data/backup
WORK_DIR=/tmp
PROJECT_NAME=tomcat-java-demo

# 拉取程式碼
cd $WORK_DIR
if [ ! -d $PROJECT_NAME ]; then
   git clone https://github.com/lizhenliang/tomcat-java-demo
   cd $PROJECT_NAME
else
   cd $PROJECT_NAME
   git pull
fi

# 構建
mvn clean package -Dmaven.test.skip=true
if [ $? -ne 0 ]; then
   echo "maven build failure!"
   exit 1
fi

# 部署
TOMCAT_PID=$(ps -ef |grep "$TOMCAT_NAME" |egrep -v "grep|$$" |awk 'NR==1{print $2}')
[ -n "$TOMCAT_PID" ] && kill -9 $TOMCAT_PID
[ -d $ROOT ] && mv $ROOT $BACKUP_DIR/${TOMCAT_NAME}_ROOT$DATE
unzip $WORK_DIR/$PROJECT_NAME/target/*.war -d $ROOT
$TOMCAT_DIR/bin/startup.sh






指令碼註釋
這是一個用於自動化部署Tomcat Java應用的bash指令碼,具體步驟如下:

1. 獲取當前日期並格式化為YYYY-MM-DD_HH:MM:SS格式存入變數DATE。
2. 接收命令列引數$1作為Tomcat例項名稱,並基於此名稱設定TOMCAT_DIR指向實際的Tomcat安裝目錄。
3. 指定ROOT為部署應用的webapps/ROOT目錄。
4. 設定備份目錄BACKUP_DIR用於備份舊版應用,工作目錄WORK_DIR用於處理克隆和構建過程。
5. 判斷專案是否已存在本地,若不存在則從GitHub上克隆tomcat-java-demo專案;若已存在則拉取最新程式碼。
6. 使用Maven清理並打包專案,跳過測試階段,如果構建失敗,則輸出錯誤資訊並退出指令碼。
7. 查詢並終止正在執行的Tomcat程序,確保使用提供的TOMCAT_NAME找到正確的程序,並殺死程序以準備部署新版本。
8. 備份當前部署在ROOT目錄下的應用程式至BACKUP_DIR,備份檔名為${TOMCAT_NAME}_ROOT$DATE。
9. 解壓縮構建生成的.war檔案到ROOT目錄,覆蓋原有內容。
10. 啟動新的Tomcat例項以載入部署的應用程式。

整體流程實現了自動從GitHub獲取專案原始碼,構建專案,停止現有Tomcat服務,備份當前部署的應用,然後部署新構建的應用,並重啟Tomcat服務。

16.自動化釋出php專案





1.拉去程式碼
2.同步程式碼 rsync


增量


#!/bin/bash
DATE=$(date +%F_%T)

WWWROOT=/usr/local/nginx/html/$1


BACKUP_DIR=/data/backup
WORK_DIR=/tmp
PROJECT_NAME=php-demo


# 拉取程式碼
cd $WORK_DIR
if [ ! -d $PROJECT_NAME ]; then
   git clone https://github.com/lizhenliang/php-demo
   cd $PROJECT_NAME
else
   cd $PROJECT_NAME
   git pull
fi


# 部署
if [ ! -d $WWWROOT ]; then
   mkdir -p $WWWROOT
   rsync -avz --exclude=.git $WORK_DIR/$PROJECT_NAME/* $WWWROOT
else
   rsync -avz --exclude=.git $WORK_DIR/$PROJECT_NAME/* $WWWROOT
fi






指令碼註釋
這個bash指令碼執行了如下的操作序列來部署PHP專案:

1. 獲取當前日期時間並格式化為YYYY-MM-DD_HH:MM:SS,儲存在變數DATE中。
2. 定義WWWROOT變數,其值為Nginx伺服器的HTML根目錄下與命令列第一個引數對應的子目錄路徑。
3. 設定備份目錄BACKUP_DIR和臨時工作目錄WORK_DIR,以及要部署的專案名稱PROJECT_NAME為php-demo。
4. 轉換工作目錄到WORK_DIR,檢查是否存在專案目錄,若不存在則從GitHub上克隆專案;若已存在,則進入專案目錄並更新程式碼(透過git pull)。
5. 在部署環節,首先檢查目標部署目錄WWWROOT是否存在:
   - 如果目標目錄不存在,建立該目錄及其所有必要的父目錄(透過mkdir -p);
   - 不論目標目錄是否已存在,都使用rsync命令同步專案中的所有檔案(除了.git目錄),從WORK_DIR下的專案目錄複製到WWWROOT目錄下。
   
整個指令碼的作用是實現一個自動化部署流程,它會從指定的GitHub倉庫拉取PHP專案程式碼,然後將其部署到Nginx伺服器的特定Web根目錄下,同時排除了Git管理的相關檔案。

17.dos攻擊防禦


點 -> 點
dos   封ip
ddos  洪水式攻擊   
原理:tcp半連線

c -> s
c <- s
c -> s


cc 攻擊  






#!/bin/bash
DATE=$(date +%d/%b/%Y:%H:%M)
LOG_FILE=/usr/local/nginx/logs/demo2.access.log
ABNORMAL_IP=$(tail -n5000 $LOG_FILE |grep $DATE |awk '{a[$1]++}END{for(i in a)if(a[i]>10)print i}')
for IP in $ABNORMAL_IP; do
    if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then
        iptables -I INPUT -s $IP -j DROP
        echo "$(date +'%F_%T') $IP" >> /tmp/drop_ip.log
    fi
done



指令碼註釋
該bash指令碼的主要功能是對最近5000條日誌中的異常IP地址進行識別並新增到防火牆規則中阻止其訪問。具體步驟如下:

1. 獲取當前日期時間格式為“天/月/年:小時:分鐘”並將其賦值給變數DATE。
2. 定義日誌檔案路徑為/usr/local/nginx/logs/demo2.access.log。
3. 透過tail命令檢視日誌檔案的最後5000行,並透過grep過濾出當天(匹配$DATE格式)的日誌行。
4. 使用awk對IP地址進行統計,如果某個IP地址出現次數大於10次,則將其加入陣列a並在結束時輸出(即這些異常IP地址)。
5. 遍歷得到的異常IP列表ABNORMAL_IP,對於每一個IP地址執行以下操作:
   - 使用iptables命令檢查當前INPUT鏈中是否已經包含了針對該IP地址的DROP規則。
   - 如果沒有包含DROP規則(iptables -vnL |grep -c "$IP"結果為0),則在INPUT鏈的頭部插入一個新的規則,拒絕來自該IP地址的所有流量。
   - 將操作時間和IP地址記錄到/tmp/drop_ip.log檔案中,便於後期審計和追蹤。

綜上所述,該指令碼主要用於監控Nginx日誌並根據訪問頻率自動封鎖高風險IP地址。

18.入侵檢測指令碼

對某個目錄裡建立  刪除檔案路徑


挖礦病毒  應用程式和系統漏洞
勒索病毒

/usr/bin
/wwwroot  篡改 注入


yum -y install inotify-tools


作為守護程序執行 nohup bash 18.sh &>/dev/null &






#!/bin/bash

MON_DIR=/opt
inotifywait -mqr --format %f -e create $MON_DIR |\
while read files; do
   rsync -avz /opt /tmp/opt
   #echo "$(date +'%F %T') create $files" | mail -s "dir monitor" xxx@163.com
done




指令碼註釋
該指令碼是一個簡單的目錄監控指令碼,使用inotifywait工具監視指定目錄(在這個例子中是/opt目錄)下的檔案建立事件。當監測到有新檔案建立時,指令碼會執行相應的操作。

inotifywait命令:
- -m 表示持續監聽模式,不會在檢測到一次事件後立即退出。
- -q 表示安靜模式,減少輸出資訊。
- -r 表示遞迴監聽指定目錄及其所有子目錄。
- --format %f 指定輸出格式為僅包含新建立檔案的名稱。
- -e create 監聽的事件型別為檔案建立。

每當在/opt目錄及其子目錄中建立了一個新檔案,inotifywait就會輸出新建立的檔名到管道(|),接下來的while迴圈會讀取這些檔名。

迴圈內部的操作:
- rsync 命令用於將/opt目錄下的所有內容同步到/tmp/opt目錄。這樣每當/opt目錄下有新檔案建立,都會觸發一次完整的目錄同步。
- 註釋掉的部分是一個郵件通知功能,原本設計在每次有新檔案建立時,會透過郵件傳送一條訊息到xxx@163.com,包含建立檔案的日期時間及檔名。

總體而言,這個指令碼旨在監控/opt目錄下檔案的變化,並在有新檔案建立時,實時地將整個/opt目錄的內容備份到/tmp/opt目錄。此外,還具備了暫時註釋掉的郵件通知功能。

相關文章