测试网络状态
[root@wenzi data]#vim ping.sh
#!/bin/bash
host=$1
ping $host -c5
if [ $? -eq 0 ];then
echo "Successful"
else
echo "Failure"
fi
[root@wenzi data]#bash ping.sh 192.168.29.142
PING 192.168.29.142 (192.168.29.142) 56(84) bytes of data.
64 bytes from 192.168.29.142: icmp_seq=1 ttl=64 time=0.396 ms
64 bytes from 192.168.29.142: icmp_seq=2 ttl=64 time=0.573 ms
64 bytes from 192.168.29.142: icmp_seq=3 ttl=64 time=0.286 ms
64 bytes from 192.168.29.142: icmp_seq=4 ttl=64 time=0.516 ms
64 bytes from 192.168.29.142: icmp_seq=5 ttl=64 time=0.412 ms
--- 192.168.29.142 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 97ms
rtt min/avg/max/mdev = 0.286/0.436/0.573/0.102 ms
Successful
[root@wenzi wenzi]# cat test.sh
#!/bin/bash
ip_list=$*
for ip in $ip_list;do
if ping -c 5 $ip > /dev/null;then
echo "$ip ping is successful"
continue
fi
echo "$ip ping is failure"
done
[root@wenzi wenzi]# ./test.sh 127.0.0.1 192.168.28.200
127.0.0.1 ping is successful
192.168.28.200 ping is failure
说明:
$* 表示除了$0以外,所有的参数,如上即 “opt1 opt2 opt3 opt4“,每个变量之间用空格分割,共用一个双引号
检测192.168.28.0/24网段内在线主机的IP地址
#!/bin/bash
ip=192.168.28
for i in `seq 1 254`;do
fullIP=$ip.$i
ping -c 3 $fullIP &> /dev/null
if [ $? -eq 0 ];then
echo "$fullIP"
fi
done
显示系统信息
[root@wenzi data]#cat systemInfo.sh
#/bin/bash
RED="\E[1;31m"
GREEN="\E[1;32m"
END="\E[0m"
echo -e "$GREEN----------------------Host systeminfo--------------------$END"
echo -e "HOSTNAME: $RED`hostname`$END"
echo -e "IPADDR: $RED`ifconfig ens160 | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -n 1`$END"
echo -e "OSVERSION: $RED`cat /etc/redhat-release`$END"
echo -e "KERNEL: $RED`uname -r`$END"
echo -e "CPU: $RED`lscpu | grep 'Model name'| tr -s ' ' | cut -d : -f 2`$END"
echo -e "MEMORY: $RED`free -h | grep 'Mem' | tr -s ' ' : | cut -d ':' -f 2`$END"
echo -e "DISK: $RED`lsblk | grep '^nv' | tr -s ' ' | cut -d " " -f 4`$END"
echo -e "$GREEN---------------------------------------------------------$END"
说明:
grep -E 开启拓展正则表达式,-o 仅显示匹配到的数据
([0-9]{1,3}\.){3}[0-9]{1,3}中[0-9]{1,3}表示1到3位数字,{3}表示重复3次,所以整体就是匹配IP地址
tr -s 对指定的字符串去重复
cut 使用对象是一行信息,-d 指定分割字符,-f 依据-d的分割字符将一段信息分为数段,用-f取出第几段
^nv 指以nv开头
批量创建用户并设置随机密码
[root@wenzi data]#cat batchCreateUser.sh
#!/bin/bash
userNum=$1
for ((i=1;i<=${userNum};i+=1))
do
useradd wenzi$i
pwd=`cat /dev/urandom | tr -d -c '[:alnum:]' | head -c 12`
echo $pwd | passwd --stdin wenzi$i &> /dev/null
echo wenzi$i:$pwd >> /data/user.log
echo "wenzi$i is created"
done
[root@wenzi data]#bash batchCreateUser.sh 5
wenzi1 is created
wenzi2 is created
wenzi3 is created
wenzi4 is created
wenzi5 is created
[root@wenzi data]#cat /data/user.log
wenzi1:aBfx6xKXXWXd
wenzi2:zeiXcSdeECga
wenzi3:XXWhxovUy9o1
wenzi4:mk6wF4gqQxbP
wenzi5:YvcHWo6UYQcP
#删除生成的用户
[root@wenzi data]#for i in {1..5};do userdel -r wenzi$i;done
说明:
/dev/urandom是随机数生成器
[:alnum:] 代表英文大小写字符及数字,即 0-9,A-Z,a-z
tr的-d选项:删除信息中指定内容;-c选项:使用指定字符串的补集替换该字符串;所以tr删除的是非'[:alnum:]'的内容
执行远程主机的脚本
#主机192.168.29.142
[root@wenzi ~]#yum -y install httpd
[root@wenzi ~]#vim /var/www/html/hello.sh
#!/bin/bash
echo "hello world"
[root@wenzi ~]#systemctl start httpd
#主机192.168.29.141
[root@wenzi data]#curl http://192.168.29.142/hello.sh | bash
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 31 100 31 0 0 31000 0 --:--:-- --:--:-- --:--:-- 31000
hello world
[root@wenzi data]#curl -s http://192.168.29.142/hello.sh | bash
hello world
rm命令的安全实现
[root@wenzi data]#vim rm.sh
#!/bin/bash
warning_color="echo -e \E[1;31m"
end="\E[0m"
dir=/tmp/`date +%F%T`
mkdir $dir
mv $* $dir
${warning_color}Move $* to $dir $end
[root@wenzi data]#chmod 777 /data/rm.sh
[root@wenzi data]#alias rm='/data/rm.sh'
[root@wenzi data]#touch {1..3}.txt
[root@wenzi data]#ll
total 4
-rw-r--r-- 1 root root 0 Jul 22 10:43 1.txt
-rw-r--r-- 1 root root 0 Jul 22 10:43 2.txt
-rw-r--r-- 1 root root 0 Jul 22 10:43 3.txt
-rw-r--r-- 1 root root 138 Jul 22 10:42 rm.sh
[root@wenzi data]#rm *.txt
Move 1.txt 2.txt 3.txt to /tmp/2023-07-2210:45:20
说明:
$*:位置变量,代表除了$0(脚本本身名字)以外,所有的参数,如上即 “opt1 opt2 opt3 opt4“,每个变量之间用空格分割,共用一个双引号
检查软件包是否安装
[root@wenzi wenzi]# cat test.sh
#!/bin/bash
pkg=$1
rpm -q $1 > /dev/null
if [ $? -eq 0 ];then
echo "$1 is already installed."
else
echo "$1 is not installed!"
fi
[root@wenzi wenzi]# ./test.sh httpd
httpd is already installed.
[root@wenzi wenzi]# ./test.sh nginx
nginx is not installed!
检查服务状态
[root@wenzi wenzi]# cat test.sh
#!/bin/bash
if pgrep $1 > /dev/null;then
echo "$1 is running"
else
echo "$1 is not running"
fi
[root@wenzi wenzi]# ./test.sh httpd
httpd is running
[root@wenzi wenzi]# ./test.sh nginx
nginx is not running
检查给定的任意一个服务运行状态
只检查服务sshd crond mysqld 中任意一个服务的状态,如果不是这3个中的服务,就提示用户能够检查的服务名并退出脚本;如果服务是运行着的就输出 "服务名 is running",如果服务没有运行就启动服务
#!/bin/bash
read -p "which service: " service
if [ $service != 'sshd' ] && [ $service != 'crond' ] && [ $service != 'mysqld' ];then
echo "Can only check sshd、crond、mysqld"
exit
else
lines=`pgrep $service | wc -l`
if [ $lines -gt 0 ];then
echo "$service is running"
else
systemctl start $service
fi
fi
监控CPU利用率
使用vmstat命令分析
具体含义见 vmstat_笔落_惊风雨的博客-CSDN博客
[root@wenzi wenzi]# cat test.sh
#!/bin/bash
dateTime=`date +'%F %T'`
ip=`ifconfig ens160 | awk 'NR==2{print $2}'`
mail="example@mail.com"
if ! which vmstat &> /dev/null;then
echo "vmstat command not found,Please install procps package"
exit 1
fi
cpuUS=`vmstat | awk 'NR==3{print $13}'`
cpuSY=`vmstat | awk 'NR==3{print $14}'`
cpuID=`vmstat | awk 'NR==3{print $15}'`
cpuWA=`vmstat | awk 'NR==3{print $16}'`
allUSE=$[$cpuUS+$cpuSY]
#当CPU利用率超过50%时发送邮件
if [ $allUSE -gt 50 ];then
echo -e "
Date: $dateTime
Host: $ip
Problem: CPU utilization $allUSE
" mail -s "CPU Monitor" $mail
fi
说明:
查询vmstat来自哪个软件包
[root@wenzi wenzi]# rpm -qf `which vmstat`
procps-ng-3.3.15-6.el8.x86_64
awk的内置变量NR表示awk处理的是第几行数据
使用管道符发送邮件 echo "邮件内容" | mail -s "邮件标题" 接收方
检测CPU剩余百分比
#!/bin/bash
dateTime=`date +'%F-%T'`
cpuResidue=`top -bn 1 | grep "Cpu" | awk -F ',' '{print $4}' | tr -d 'id' | tr -d ' '`
echo "$dateTime cpuResidue is $cpuResidue%"
说明:
top 的 -b 表示以批处理模式操作;-n 表示循环显示的次数。即将输出top的此刻数据
监控内存利用率
[root@wenzi wenzi]# free -m
total used free shared buff/cache available
Mem: 791 181 274 5 335 477
Swap: 2047 0 2047
[root@wenzi wenzi]# cat test.sh
#!/bin/bash
total=`free -m | awk '/Mem/ {print $2}'`
used=`free -m | awk '/Mem/ {print $2-$4-$6}'`
#获取相除的值
memUtilization=$(printf "%4.2f" `echo "scale=2;$used/$total" | bc`)
#获取没有百分号的百分比
memUti=$(printf "%2.0f" `echo "$memUtilization*100" | bc`)
if [ $memUti -gt 0 ];then
echo "Memory utilization is $memUti%"
fi
说明:
内存利用率计算见 free_笔落_惊风雨的博客-CSDN博客
awk '/Mem/ {print $2}' 表示直接定位到Mem所在行,然后取第二个字符。 /Mem/ 是awk的模式匹配之一,表示匹配包含Mem的行,格式 /正则表达式/ 表示使用通配符的拓展集。
printf语法:printf ‘打印格式’ 实际内容。printf "%4.2f" 表示长度为4个字符的具有小数点的字段,其中小数位占2个字符宽度,小数点占1个字符宽度。
echo "scale=2;$used/$total" | bc 表示计算$used除以$total,保留两位小数后的值。bc计算时若值小于1,显示时会省去个位的0。
为了保留个位的0,所以使用printf再次处理。
printf 和 bc 结合使用,写法 $(printf "%4.2f" `echo "scale=2;$used/$total" | bc`)
监控磁盘利用率
[root@wenzi wenzi]# cat test.sh
#!/bin/bash
diskList=`df -h | grep "^/dev/" | sort`
diskListLineNums=`echo $diskList | wc -l`
for i in $diskListLineNums;do
diskUsed=`echo $diskList | awk '{print $5}' | awk -F '%' '{print $1}'`
#当使用率达到50告警
if [ $diskUsed -gt 50 ];then
dev=`echo $diskList | awk '{print $1}'`
devSize=`echo $diskList | awk '{print $2}'`
echo "$dev is used $diskUsed% , Warning!"
fi
done
[root@centos8 ~]#df -Th | grep "^/dev" | awk '{print $1,$6}'
/dev/mapper/cl-root 5%
/dev/mapper/cl-data 1%
/dev/nvme0n1p1 22%
检测剩余inode
[root@wenzi ~]# df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
devtmpfs 97117 376 96741 1% /dev
tmpfs 101311 1 101310 1% /dev/shm
tmpfs 101311 558 100753 1% /run
tmpfs 101311 17 101294 1% /sys/fs/cgroup
/dev/sda3 8912384 38010 8874374 1% /
/dev/sda1 65536 309 65227 1% /boot
tmpfs 101311 5 101306 1% /run/user/0
[root@wenzi wenzi]# vim test.sh
#!/bin/bash
dateTime=`date +'%F-%H-%M-%S'`
iFree=` df -i | grep -v "Filesystem" | awk '{print $4}'`
for i in $iFree;do
if [ $i -lt 200 ];then
fileSys=`df -i | grep "$i" | awk '{print $1}'`
echo "Date: $dateTime $fileSys inode is less than 200"
fi
done
检查网站可用性
[root@wenzi wenzi]# cat test.sh
#!/bin/bash
check_url() {
httpCode=`curl -o /dev/null --connect-timeout 3 -s -w "%{http_code}" $1`
if [ $httpCode -ne 200 ];then
echo "Warning: $1 is failure!"
fi
}
check_url $1
说明:
curl中 -o 表示将下载数据写入指定名称的文件中;--connect-timeout 表示最大请求时间;-w 表示在请求结束后打印本次请求的统计数据到标准输出,curl提供很多内置变量,使用 %{变量} 调用,完整的内置变量查看 man curl。
用户根据菜单选择要连接的Linux主机
[root@wenzi wenzi]# vim test.sh
#!/bin/bash
PS3="Please enter serial number: "
hostFile=/root/wenzi/hostList.txt
select i in `awk '{print $1}' $hostFile`;do
[ ${i:=quit} == "quit" ] && exit 0
ip=`awk -v name=${i} '$1==name{print $2}' $hostFile`
user=`awk -v name=${i} '$1==name{print $3}' $hostFile`
port=`awk -v name=${i} '$1==name{print $4}' $hostFile`
if [ -n $IP ];then
echo "Name: $i, IP: $ip"
ssh -o StrictHostKeyChecking=no -p $port -i /root/.ssh/id_rsa $user@$ip
break
fi
说明:
PS3 是一个预定义的变量,用于指定输入提示符。
select 语句用于创建一个交互式的菜单,并接收用户的选择。不遇到exit或break不会停下。
${i:=quit} 表示 i 没有设定时 i 的值为quit,i 是空字符串时 i 的值为quit,i 已设定为非空字符串时,i 的值不变。在脚本中即输入的序号存在时,才会执行下面的脚本,否则 i 的值为quit,和等号后面的 quit 一致,会执行exit 0,退出脚本。见 认识与学习Bash_笔落_惊风雨的博客-CSDN博客
awk -v name=${i} 表示将外部的$i变量的值传递给awk,awk以变量name接收,此name只在awk内生效,外部无法调用。$1=name是条件判断
扫描主机端口状态
[root@wenzi wenzi]# cat test.sh
#!/bin/bash
read -p "Please enter IP: " ip
while true;do
read -p "Please enter Port: " port
if [ $port == "quit" ];then
break
fi
if nc -n -z -w2 $ip $port &> /dev/null;then
echo "$port is open"
else
echo "$port is close"
fi
done
说明:
借助nc(来自netcat软件包)命令进行检测,-n 表示使用IP地址;-z 表示使用0输入/输出模式,只在扫描通信端口时使用;-w 表示超时秒数
实现SSH登录免交互执行命令
[root@wenzi wenzi]# cat test.sh
#!/bin/bash
ip=192.168.28.141
user=root
passwd=admin
expect << EOF
#设置超时时间
set timeout 10
#开启ssh连接,固定语法
spawn ssh $user@$ip
expect {
"(yes/no)" {send "yes\r"; exp_continue}
"password:" {send "$passwd\r"}
}
expect "$user@*" {send "$1\r"}
expect "$user@*" {send "exit\r"}
# expect结束标志,spawn收到eof后会结束之前开启的进程
expect eof
EOF
#需要输入一个参数,计划在远程主机上执行的命令
[root@wenzi wenzi]# ./test.sh pwd
spawn ssh root@192.168.28.141
Last login: Thu Sep 7 19:08:10 2023 from 192.168.28.158
[root@wenzi ~]# pwd
/root
[root@wenzi ~]# exit
logout
Connection to 192.168.28.141 closed.
说明:
需要安装expect软件包;可以模拟用户在终端上的输入和输出,并与交互式程序进行交互。
expect_continue 在上方表示在匹配到yes或no时,继续等待下一个匹配,而不是退出循环
批量修改服务器用户密码
[root@wenzi wenzi]# cat oldPass.txt
192.168.28.156 root admin 22
[root@wenzi wenzi]# vim test.sh
#!/bin/bash
oldPassFile=/root/wenzi/oldPass.txt
newPassFile=/root/wenzi/newPass.txt
for i in `awk '{print $1}' $oldPassFile`;do
user=`awk -v ip=$i 'ip==$1{print $2}' $oldPassFile`
oldPwd=`awk -v ip=$i 'ip==$1{print $3}' $oldPassFile`
port=`awk -v ip=$i 'ip==$1{print $4}' $oldPassFile`
newPass=`cat /dev/urandom | tr -d -c "[:alnum:]" | head -c 12`
echo $i $user $newPass $port >> $newPassFile
expect << EOF
spawn ssh -p $port $user@$i
set timeout 10
expect {
"(yes/no" {send "yes\r";exp_continue}
"password:" {send "$oldPwd\r";exp_continue}
"$user@" {send "echo $newPass | passwd --stdin $user;exit\r"}
}
expect eof
EOF
done
数据库备份
#!/bin/bash
dateTime=`date +'%Y%m%d%H%M%S'`
host=192.168.28.158
user=root
password=Admin.123
database=cs
bakDir=/data/backup
mysqldump -u$user -p${password} --single-transaction -R --triggers -B $database > $bakDir/$dateTime-all.sql
if [ $? -eq 0 ];then
echo "backup success"
else
echo "backup failure"
fi
#自动删除30天前的备份
find $bakDir -name "*all.sql" -mtime +30 -exec rm -f {} \;
检查mysql主从结构中从数据库的状态
- 本机的数据库服务是否正在运行
- 能否与主数据库服务器正常通信
- 能否使用授权用户连接数据库服务器
- 本机的slave_IO进程是否处于YES状态
- 本机的slave_SQL进程是否处于YES状态
#!/bin/bash
#检测mysql服务是否运行
lines=`pgrep mysqld | wc -l`
if [ $lines -gt 0 ];then
echo "mysqld is running!"
else
systemctl start mysqld
fi
#检测与主数据库能否通信
ping -c 3 192.168.28.158 &> /dev/null
if [ $? -eq 0 ];then
echo "ping is sueccess!"
else
echo "ping is failure!"
fi
#检测用户能否连接数据库服务器
host=192.168.28.158
user=rep
password='Admin.123'
mysql -h $host -u$user -p$password -e 'quit' &> /dev/null
if [ $? -eq 0 ];then
echo "connect is sueccess!"
else
echo "connect is failure!"
fi
#检测本机IO线程和SQL线程
IO=`mysql -uroot -p'Admin.123' -e "show slave status\G" 2> /dev/null | grep 'Slave_IO_Running:' | awk '{print $2}'`
SQL=`mysql -uroot -p'Admin.123' -e "show slave status\G" 2> /dev/null | grep 'Slave_SQL_Running:' | awk '{print $2}'`
if [ $IO == 'Yes' ] && [ $SQL == 'Yes' ];then
echo "IO and SQL connect success"
else
echo "IO and SQL connect failure"
说明:
mysql -uroot -p'Admin.123' -e "show slave status\G" 2> /dev/null 中2> /dev/null是为了排除mysql明文登录时的Warning信息
PV过量实现防火墙自动封禁IP
仅供参考,未经过实测,AI修正后的脚本
#!/bin/bash
log=/tmp/tmp.log
[ -f $log ] || touch $log
function add_iptales {
while read line
do
ip=$(echo $line | awk '{print $2}')
count=$(echo $line | awk '{print $1}')
if [ $count -gt 100 ] && [ $(iptables -L -n | grep "$ip" | wc -l) -lt 1 ]
then
iptables -I INPUT -s $ip -j DROP
echo -e "$ip is dropped" >> /tmp/droplist.log
fi
done < $log
}
function main {
while true
do
netstat -an | grep "EST" | awk -F '[:]+' '{print $6}' | sort | uniq -c >> $log
add_iptales
sleep 180
done
}
main
说明:
PV(Page View)是指页面浏览量,通常是衡量网站或网页流量和活跃度的主要指标。在网络安全领域,PV过量通常指的是某个IP地址对特定网站或服务产生了过高的页面浏览量,这可能会引起防火墙的封锁。
检测服务器网卡流量
#!/bin/bash
#收集网卡名称,本地回环口lo除外
interfaces=`ifconfig | awk -F ':' '/flags/ {print$1}' | grep -v 'lo'`
for i in $interfaces;do
ip=`ifconfig ens160 | awk 'NR==2 {print $2}'`
rxBytes=`ifconfig ens160 | grep "RX packets" | awk '{print $6 $7}' | tr -d '()'`
txBytes=`ifconfig ens160 | grep "TX packets" | awk '{print $6 $7}' | tr -d '()'`
echo -e "网卡:$i\nIP:$ip\n下行流量:$rxBytes\n上行流量:$txBytes"
done