shell 實(shí)戰(zhàn)常用命令服務(wù)器系統(tǒng)一些配置初始化(centos7)
發(fā)送告警郵件
批量創(chuàng)建用戶(hù)
查看資源利用率
找出占用CPU/內(nèi)存過(guò)高的進(jìn)程
查看網(wǎng)卡實(shí)時(shí)流量
監(jiān)控批量服務(wù)器磁盤(pán)利用率
--1.批量就需要免密登錄
--2.expec 免交互輸入密碼
檢測(cè)網(wǎng)站運(yùn)行正常目錄文件變化和同步
mysql 備份監(jiān)控
MySQL 主從同步狀態(tài)
Nginx 訪(fǎng)問(wèn)日志分析
自動(dòng)屏蔽高訪(fǎng)問(wèn)IP
LNMP環(huán)境搭建
python 調(diào)用shell 命令
服務(wù)器系統(tǒng)一些配置初始化(centos7)
> cat /proc/version
>
> Linux version 5.4.0-72-generic (buildd@lcy01-amd64-019) (gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)) #80-Ubuntu SMP Mon Apr 12 17:35:00 UTC 2021
>
> cat /etc/lsb-release
> DISTRIB_ID=Ubuntu
> DISTRIB_RELEASE=20.04
> DISTRIB_CODENAME=focal
> DISTRIB_DESCRIPTION="Ubuntu 20.04.2 LTS"
>
> cat /etc/redhat-release
> CentOS Linux release 7.8.2003 (Core)
#/bin/bash
# 設(shè)置時(shí)區(qū)并同步時(shí)間
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 注意這種if 的寫(xiě)法是可以的, 如果grep沒(méi)找到就返回Fasle, 還有可以用[] 做表達(dá)式
if ! crontab -l |grep ntpdate &>/dev/null ; then
# 同步時(shí)間 ntpdate time.windows.com
# () 內(nèi)作為一組去執(zhí)行
# |crontab 可以將前面的輸入寫(xiě)到文件中
# crontab -l 可以把前面的命令以新增的方式寫(xiě)入crontab, 不加他會(huì)覆蓋所有之前的crontab
(echo "* 1 * * * ntpdate time.windows.com >/dev/null 2>&1";crontab -l) |crontab
fi
# 禁用selinux, 不關(guān)閉可能會(huì)因?yàn)槟涿畹臋?quán)限問(wèn)題導(dǎo)致服務(wù)不通
# 這里匹配到SELINUX 這一行, 然后s/before/after 去替換, 和vim 里的:%s/before/after/g 一樣
sed -i '/SELINUX/{s/permissive/disabled/}' /etc/selinux/config
# 關(guān)閉防火墻
# egrep 后面接正則匹配, 匹配到就為T(mén)rue
# centos 7 用firewall 替代 iptables
if egrep "7.[0-9]" /etc/redhat-release &>/dev/null; then
systemctl stop firewalld
systemctl disable firewalld
elif egrep "6.[0-9]" /etc/redhat-release &>/dev/null; then
service iptables stop
chkconfig iptables off
fi
# 歷史命令顯示操作時(shí)間, 只要設(shè)置這個(gè)系統(tǒng)變量HISTTIMEFORMAT 即可, %F日期, %T時(shí)間
# >> 增量寫(xiě)入
if ! grep HISTTIMEFORMAT /etc/bashrc; then
echo 'export HISTTIMEFORMAT="%F %T `whoami` "' >> /etc/bashrc
fi
# SSH超時(shí)時(shí)間
if ! grep "TMOUT=600" /etc/profile &>/dev/null; then
echo "export TMOUT=600" >> /etc/profile
fi
# 禁止root遠(yuǎn)程登錄, 提前確定還有其他用戶(hù)可以登錄
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
# 禁止定時(shí)任務(wù)向發(fā)送郵件
# 如果定時(shí)任務(wù)沒(méi)有加到重定向?yàn)榭? >/dev/null 2>&1, 它的標(biāo)準(zhǔn)輸出、錯(cuò)誤都會(huì)向當(dāng)前用戶(hù)發(fā)送一封郵件, 存到 /var/mail/
# mailto為空就不會(huì)發(fā)送
# s/before/after/ 替換
sed -i 's/^MAILTO=root/MAILTO=""/' /etc/crontab
# 設(shè)置最大打開(kāi)文件數(shù), 默認(rèn)是1024, 并發(fā)數(shù)高的時(shí)候很容易達(dá)到
# 將 soft hard 兩行內(nèi)容追加到 limits.conf中(*前面的空格也會(huì)寫(xiě)進(jìn)去)
# EOF 要頂?shù)筋^, 否則會(huì)出錯(cuò)
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
# 系統(tǒng)內(nèi)核優(yōu)化
cat >> /etc/sysctl.conf << EOF
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_tw_buckets = 20480
net.ipv4.tcp_max_syn_backlog = 20480 # 默認(rèn)是128
net.core.netdev_max_backlog = 262144 # 網(wǎng)卡最大的隊(duì)列長(zhǎng)度
net.ipv4.tcp_fin_timeout = 20 # 四次揮手?jǐn)嚅_(kāi)的一個(gè)超時(shí)時(shí)間
EOF
# 減少SWAP使用, 設(shè)置的是一個(gè)權(quán)重值, 值越大, 使用swap 的可能性越大,0 不使用
# swap 比物理內(nèi)存要慢很多, 但是也不要關(guān)閉他
echo "0" > /proc/sys/vm/swappiness
# 安裝系統(tǒng)性能分析工具及其他
yum install gcc make autoconf vim sysstat net-tools iostat iftop iotp lrzsz -y
dos2unix
有時(shí)候 windows 編輯的shell 文件在linux 中可能有格式、語(yǔ)法錯(cuò)誤
用dos2unix 轉(zhuǎn)一下
yum install dos2unix -y
dos2unix shell_file.sh
發(fā)送告警郵件
系統(tǒng)默認(rèn)發(fā)送郵件,用sendmail , 顯示默認(rèn)的發(fā)送人是主機(jī)名(會(huì)被當(dāng)做垃圾郵件) 而且有延遲
所有, 用外部郵箱服務(wù)器, 例如 163 (需要在郵箱設(shè)置中開(kāi)啟 SMTP)
yum install mailx -y
# yum install mailx
# vi /etc/mail.rc
set from=test@163.com smtp=smtp.163.com
set smtp-auth-user=test@163.com smtp-auth-password=123456
set smtp-auth=login
測(cè)試
echo "this is a test content" | mail -s "subject name" test@163.com
批量創(chuàng)建用戶(hù)
addusers.txt
user1 pwd1
user2 pwd2
#!/bin/bash
USERS_FILE=addusers.txt
USERADD=/usr/sbin/useradd
PASSWD=/usr/bin/passwd
# 循環(huán)讀文件
while read line
do
# cut 通過(guò) 空格分隔, -f1 第一個(gè)
USERNAME=`echo $line | cut -f1 -d ' '`
PASSWORD=`echo $line | cut -f2 -d ' '`
$USERADD $USERNAME
# $? 上一條命令的返回值, 0是 true, ne: not equal
if [[ $? ne 0 ]]; then
echo "$USERNAME has exited;skip set passwd"
else
echo "$PASSWORD | $PASSWD --stdin $USERNAME"
fi
done <$USERS_FILE
if [ 1 -ne 1 ];then
...
fi
-eq:等于
-ne:不等于
-le:小于等于
-ge:大于等于
-lt:小于
-gt:大于
[root@VM-0-15-centos ~]# passwd --help
Usage: passwd [OPTION...] <accountName>
-x, --maximum=DAYS maximum password lifetime (root only)
-n, --minimum=DAYS minimum password lifetime (root only)
-w, --warning=DAYS number of days warning users receives before password expiration (root only)
-i, --inactive=DAYS number of days after password expiration when an account becomes disabled (root only)
-S, --status report password status on the named account (root only)
--stdin read new tokens from stdin (root only)
升級(jí)版
#!/bin/bash
# 1.隨機(jī)密碼
# 2.用戶(hù)是否已經(jīng)存在
# 會(huì)接收所有的位置參數(shù)
USER_LIST=$@
USER_FILE=user.txt
for USER in $USER_LIST; do
# 通過(guò)id 查看用戶(hù)是否存在
if ! id $USER &>/dev/null; then
# cut -c
PASS=$(echo $RANDOM |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
重點(diǎn)
[root@VM-0-15-centos ~]# id root
uid=0(root) gid=0(root) groups=0(root)
[root@VM-0-15-centos ~]# id ken
id: ken: no such user
# 生成隨機(jī)值, 然后取他的 md5
[root@VM-0-15-centos ~]# echo $RANDOM
18466
[root@VM-0-15-centos ~]# echo $RANDOM|md5sum
7841fac0faa769963c0ade1107ff3e80 -
[root@VM-0-15-centos ~]# echo "12345678" | cut -c 1-5
12345
# cut -d 通過(guò)空格分隔(其他分隔符也可以)
# cut -c 截取字符
# -f1 取分隔后的第一個(gè)
cut -f1 -d ' '
[root@VM-0-15-centos ~]# echo {1..10}
1 2 3 4 5 6 7 8 9 10
grep
# 在當(dāng)前目錄所有文件查詢(xún)關(guān)鍵字 modified
grep "modified" *
# 查看關(guān)鍵字前后10行
cat file_name.txt | grep "something" -C 10
# 監(jiān)聽(tīng)本機(jī)網(wǎng)卡 eth0 端口8299 的請(qǐng)求, 然后查看 User-Agent 前后10行
tcpdump -i eth0 -A port 8299 |grep 'User-Agent' -C 10
grep 關(guān)鍵字 -A 10 查看關(guān)鍵字后10行
-B 10 查看關(guān)鍵字前10行
查看資源利用率
1.cpu 60%
2.內(nèi)存 利用率
3.硬盤(pán) 利用率
4.TCP 連接狀態(tài) (查看并發(fā)情況)
可通過(guò)top 查看使用情況, 也可以使用vmstat
wa 表示I/O wait CPU等待磁盤(pán)相應(yīng)占用cpu 的百分比, 如果到了3%~5% 當(dāng)前機(jī)器讀寫(xiě)就會(huì)很慢
[root@VM-0-15-centos ~]# vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
4 0 0 618712 45888 189752 0 0 13 25 187 404 1 0 99 0 0
netstat
-a all
-t tcp
-n numbric
-p pid/name
ESTABLISHED 說(shuō)明正在建立通信, 相當(dāng)于并發(fā), 反應(yīng)這臺(tái)機(jī)器的網(wǎng)絡(luò)連接承載量
SYN_SENT 建立三次握手期間的狀態(tài), 還沒(méi)正式建立完握手開(kāi)始通信
LISTEN 本地監(jiān)聽(tīng)的服務(wù)
[root@VM-0-15-centos ~]# netstat -atnp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 980/sshd
tcp 0 28 10.206.0.15:22 218.82.138.5:62795 ESTABLISHED 31974/sshd: root@pt
tcp 0 0 10.206.0.15:42786 169.254.0.55:5574 ESTABLISHED 1802/YDService
#!/bin/bash
function cpu() {
NUM=1
while [ $NUM -le 3 ]; do
util=`vmstat |awk '{if(NR==3)print 100-$15"%"}'`
user=`vmstat |awk '{if(NR==3)print $13"%"}'`
sys=`vmstat |awk '{if(NR==3)print $14"%"}'`
iowait=`vmstat |awk '{if(NR==3)print $16"%"}'`
echo "CPU - 使用率: $util , 等待磁盤(pán)IO響應(yīng)使用率: $iowait"
let NUM++
sleep 1
done
}
function memory() {
# printf 格式化輸出 "%.1f" 保留一個(gè)小數(shù)點(diǎn) 后面要加逗號(hào)
total=`free -m |awk '{if(NR==2)printf "%.1f",$2/1024}'`
# $NF 表示最后一列
used=`free -m |awk '{if(NR==2) printf "%.1f",($2-$NF)/1024}'`
available=`free -m |awk '{if(NR==2) printf "%.1f",$NF/1024}'`
echo "內(nèi)存 - 總大小: ${total}G , 使用: ${used}G , 剩余: ${available}G"
}
function disk() {
# awk '/^\/dev/{print $1}' 先匹配在輸出, 匹配/dev開(kāi)頭的 然后/需要\轉(zhuǎn)義
fs=$(df -h |awk '/^\/dev/{print $1}')
for p in $fs; do
mounted=$(df -h |awk '$1=="'$p'"{print $NF}')
size=$(df -h |awk '$1=="'$p'"{print $2}')
used=$(df -h |awk '$1=="'$p'"{print $3}')
used_percent=$(df -h |awk '$1=="'$p'"{print $5}')
echo "硬盤(pán) - 掛載點(diǎn): $mounted , 總大小: $size , 使用: $used , 使用率: $used_percent"
done
}
function tcp_status() {
# awk [$6]++ 會(huì)把第六列的值作為key, 個(gè)數(shù)作為value, 遇到一個(gè)就+1, 然后++遍歷完所有的
summary=(netstat -tanp |awk '{status[$6]++}END{for(i in status)printf i":"status[i]" "}')
echo "TCP連接狀態(tài) - $summary"
}
# 調(diào)用函數(shù)
cpu
memory
disk
tcp_status
重點(diǎn)
awk
awk 的處理和數(shù)據(jù)庫(kù)比較類(lèi)似
列 $2 第二列
行 NR==2 第二行
# 打印文件第二行第二列
cat users.txt | awk '{if (NR==2) print $2}'
找出占用CPU/內(nèi)存過(guò)高的進(jìn)程
ps
-O format
Like -o, but preloaded with some default columns. Identical to -o pid,format,state,tname,time,command or -o pid,format,tname,time,cmd, see -o below.
-e
user 用戶(hù)名
uid 用戶(hù)號(hào)
pid 進(jìn)程號(hào)
ppid 父進(jìn)程號(hào)
size 內(nèi)存大小, Kbytes字節(jié).
vsize 總虛擬內(nèi)存大小, bytes字節(jié)(包含code+data+stack)
share 總共享頁(yè)數(shù)
nice 進(jìn)程優(yōu)先級(jí)(缺省為0, 最大為-20)
priority(pri) 內(nèi)核調(diào)度優(yōu)先級(jí)
pmem 進(jìn)程分享的物理內(nèi)存數(shù)的百分比
trs 程序執(zhí)行代碼駐留大小
rss 進(jìn)程使用的總物理內(nèi)存數(shù), Kbytes字節(jié)
time 進(jìn)程執(zhí)行起到現(xiàn)在總的CPU暫用時(shí)間
stat 進(jìn)程狀態(tài)
cmd(args) 執(zhí)行命令的簡(jiǎn)單格式
#!/bin/bash
echo "---------------- cpu top 10 ----------------------"
ps -eo user,pid,pcpu,pmem,args --sort=-pcpu |head -n 10
echo "---------------- memory top 10 -------------------"
ps -eo user,pid,pcpu,pmem,args --sort=-pmem |head -n 10
查看網(wǎng)卡實(shí)時(shí)流量
查看網(wǎng)卡有2個(gè)地方 , 可以看到從開(kāi)機(jī)到現(xiàn)在收到和發(fā)出的流量
ifconfig
cat /proc/net/dev
? cat /proc/net/dev
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
eth0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
eth1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
#!/bin/bash
# 網(wǎng)卡名通過(guò)位置傳參, 因?yàn)槊總€(gè)機(jī)器網(wǎng)卡名可能不同
NIC=$1
echo -e " In ------ Out"
while true; do
# $0~ 一整行 包含網(wǎng)卡名 $NIC, 下面還有一直用寫(xiě)法, 上面用過(guò)
OLD_IN=$(awk '$0~"'$NIC'"{print $2}' /proc/net/dev)
# OLD_IN=$(cat /proc/net/dev | awk '/$NIC/{print $2}')
OLD_OUT=$(awk '$0~"'$NIC'"{print $10}' /proc/net/dev)
sleep 1
NEW_IN=$(awk '$0~"'$NIC'"{print $2}' /proc/net/dev)
NEW_OUT=$(awk '$0~"'$NIC'"{print $10}' /proc/net/dev)
# 開(kāi)始計(jì)算和前一秒的差值
# "%.1f%s" 保留一個(gè)小數(shù)點(diǎn), %s 是后面的值
# (( )) 雙括號(hào)是計(jì)算
IN=$(printf "%.1f%s" "$((($NEW_IN-$OLD_IN)/1024))" "KB/s")
OUT=$(printf "%.1f%s" "$((($NEW_OUT-$OLD_OUT)/1024))" "KB/s")
echo "$IN $OUT"
sleep 1
done
監(jiān)控批量服務(wù)器磁盤(pán)利用率
前置知識(shí)
1.批量就需要免密登錄
# 1. 密鑰
ssh-keygen -t rsa
# this user must have sudo permission
ssh-copy-id -i ~/.ssh/id_rsa.pub username@192.168.91.135
# 2.another way: 2 steps
$ scp ~/.ssh/id_rsa.pub root@<remote_ip>:pub_key //將文件拷貝至遠(yuǎn)程服務(wù)器
$ cat ~/pub_key >>~/.ssh/authorized_keys //將內(nèi)容追加到authorized_keys文件中, 不過(guò)要登錄遠(yuǎn)程服務(wù)器來(lái)執(zhí)行這條命令
3.將本地id_rsa.pub文件的內(nèi)容拷貝至遠(yuǎn)程服務(wù)器的~/.ssh/authorized_keys文件中
然后 就可以免密碼登錄了
ssh -i .ssh/id_rsa username@192.168.91.135
2.expec 免交互輸入密碼
# ssh 后面接命令就可以直接拿到執(zhí)行返回結(jié)果
ssh username@192.168.91.135 'df -h'
#!/bin/bash
HOST_INFO=host.info
# ^[^#] 去掉#開(kāi)頭的
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)
TMP_FILE=/tmp/disk.tmp
ssh -p $PORT $USER@$IP 'df -h' > $TMP_FILE
# int() 取整,去掉20% 中的%
USE_RATE_LIST=$(awk 'BEGIN{OFS="="}/^\/dev/{print $NF,int($5)}' $TMP_FILE)
for USE_RATE in $USE_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
expect
#!/bin/bash
# 這里用 $* 因?yàn)橐裝ash 1.sh df -h sh后面的命令df -h作為一個(gè)整體
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 {
# \r 換行
\"(yes/no)\" {send \"yes\r\"; exp_continue}
\"password:\" {send \"$PASS\r\"; exp_continue}
\"$USER@*\" {send \"$COMMAND\r exit\r\"; exp_continue}
}
"
echo "-------------------"
done
也可以通過(guò)
#!/bin/bash
USERS_FILE=host.info
# 循環(huán)讀文件
while read line
do
HOST=`echo $line | cut -f1 -d ' '`
USER=`echo $line | cut -f2 -d ' '`
PORT=`echo $line | cut -f3 -d ' '`
echo "$HOST, $USER, $PORT"
done <$USERS_FILE
或者可以通過(guò)ansible 批量管理
檢測(cè)網(wǎng)站運(yùn)行正常
#!/bin/bash
URL_LIST="www.baidu.com www.jd.com"
for URL in $URL_LIST; do
FAIL_COUNT=0
for ((i=1;i<=3;i++)); do
# curl -o output FILE
# -s silent 不輸出任何內(nèi)容
# -w 輸出指定格式的內(nèi)容到標(biāo)準(zhǔn)輸出
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"
# FAIL_COUNT 加一
let FAIL_COUNT++
fi
done
if [ $FAIL_COUNT -eq 3 ]; then
echo "Warning: $URL Access failure!"
fi
done
目錄文件變化和同步
一些病毒(挖礦)會(huì)入侵系統(tǒng)后, 新建上傳文件, 執(zhí)行腳本
/usr/bin
/wwwroot 串改, 注入
#!/bin/bash
# 需要先裝工具 yum install inotify-tools -y
# 這個(gè)工具可以監(jiān)控目錄下文件的增刪改
# -mrq 持續(xù)監(jiān)聽(tīng), 遞歸形式, 減少冗余信息輸出
# -e 監(jiān)聽(tīng)的事件, 增刪改查等
MON_DIR=/opt
inotifywait -mqr --format %f -e create $MON_DIR |\
while read files; do
# rsync 可以將2個(gè)目錄同步
rsync -avz /opt /tmp/opt
#echo "$(date +'%F %T') create $files" | mail -s "dir monitor" xxx@163.com
done
后臺(tái)運(yùn)行
nohub bash monitor.sh &>/dev/null &
mysql 備份
備份庫(kù)
mysqldump -hxxx -uroot -pxxx -B DB_name > DB.sql
備份表
mysqldump -hxxx -uroot -pxxx DB_name table_name > table.sql
#!/bin/bash
# 時(shí)間格式
DATE=$(date +%F_%H-%M-%S)
HOST=localhost
# 備份就用一個(gè)最小權(quán)限的用戶(hù) 只能查看要備份的那部分, 只讀
USER=backup
PASS=123.com
BACKUP_DIR=/data/db_backup
# egrep -v 過(guò)濾掉包含這些資源的行
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")
# 分庫(kù)備份
for DB in $DB_LIST; do
BACKUP_NAME=$BACKUP_DIR/${DB}_${DATE}.sql
# -B 指定庫(kù)
if ! mysqldump -h$HOST -u$USER -p$PASS -B $DB > $BACKUP_NAME 2>/dev/null; then
echo "$BACKUP_NAME 備份失敗!"
fi
done
# 分表備份
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
監(jiān)控MySQL 主從同步狀態(tài)
mysql -h$HOST -u$USER -p$PASSWD -e 'show slave status\G' 2>/dev/null |awk '/Slave_.*_Running:/{print $1$2}'
Slave_IO_Running: Connecting
Slave_SQL_Running: Yes
#!/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
Nginx 訪(fǎng)問(wèn)日志分析
#!/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 "統(tǒng)計(jì)訪(fǎng)問(wèn)最多的10個(gè)IP"
# awk $1 第一個(gè)字段ip, 做count 統(tǒng)計(jì), 然后排序
# sort -k2 按照第二列排序
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 "統(tǒng)計(jì)時(shí)間段訪(fǎng)問(wèn)最多的IP"
# awk 中可以直接對(duì)時(shí)間進(jìn)行比較,分析某個(gè)時(shí)間段的日志
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 "統(tǒng)計(jì)訪(fǎng)問(wèn)最多的10個(gè)頁(yè)面"
# length(a) 去重后列表內(nèi)元素個(gè)數(shù)
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 "統(tǒng)計(jì)訪(fǎng)問(wèn)頁(yè)面狀態(tài)碼數(shù)量"
awk '{a[$7" "$9]++}END{for(v in a){if(a[v]>5)print v,a[v]}}' $LOG_FILE |sort -k3 -nr
自動(dòng)屏蔽高訪(fǎng)問(wèn)IP
這里是監(jiān)控nginx 訪(fǎng)問(wèn)日志
#!/bin/bash
DATE=$(date +%d/%b/%Y:%H:%M)
LOG_FILE=/usr/local/nginx/logs/demo2.access.log
# 訪(fǎng)問(wèn)最后5000 條日志, 過(guò)濾ip出現(xiàn)10次以上的
ABNORMAL_IP=$(tail -n5000 $LOG_FILE |grep $DATE |awk '{a[$1]++}END{for(i in a)if(a[i]>100)print i}')
for IP in $ABNORMAL_IP; do
if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then
# 通過(guò)iptables
iptables -I INPUT -s $IP -j DROP
echo "$(date +'%F_%T') $IP" >> /tmp/drop_ip.log
fi
done
同樣 ssh 防暴力破解 也可以通過(guò)這種方式來(lái)屏蔽
/var/log/audit/audit.log 是系統(tǒng)審計(jì)日志, 可以通過(guò)這個(gè)日志來(lái)統(tǒng)計(jì)
LNMP環(huán)境搭建
#!/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
# openssl-devel https
# pcre-devel nginx 正則支持
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
# $1 相當(dāng)于傳參
command_status_check "Nginx - 平臺(tái)環(huán)境檢查失??!"
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 - 啟動(dòng)失?。?
}
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 - 平臺(tái)環(huán)境檢查失?。?
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 - 啟動(dòng)失?。?
}
read -p "請(qǐng)輸入編號(hào):" number
case $number in
1)
install_nginx;;
2)
install_php;;
3)
install_mysql;;
4)
install_nginx
install_php
;;
9)
exit;;
esac
bash -x test.sh 可以查看shell的執(zhí)行過(guò)程
#/bin/bash
echo $0(代表命令本身);
echo $1; (代表第幾個(gè)參數(shù))
echo $2;
[root@LocalWeb01 ~]# ./1.sh 2 3
./1.sh
2
3
$#代表參數(shù)個(gè)數(shù)
$* 代表命令行的 所有參數(shù)代表一個(gè)整體
$@ 代表命令行的 所有參數(shù)代表一個(gè)整體,不過(guò)把每個(gè)參數(shù)區(qū)分對(duì)待
$? 上條命令執(zhí)行是否成功 0是成功
$$ 當(dāng)前運(yùn)行的進(jìn)程號(hào)
$! 后臺(tái)運(yùn)行的最后一條的進(jìn)程號(hào)
python 調(diào)用shell 命令
import subprocess
return_code, res = subprocess.getstatusoutput('pwd')
print(return_code, res)
遇到比較復(fù)雜的shell 腳本, 也可以用python 處理源文件
然后生成shell 腳本, 執(zhí)行腳本
或者直接調(diào)用shell 命令