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目录。此外,还具备了暂时注释掉的邮件通知功能。