获取随机8位字符串
方法1:
# echo $RANDOM |md5sum |cut -c 1-8
c9f36977
#这个命令使用$RANDOM变量生成一个随机的整数,然后将其经过MD5哈希处理,并使用cut命令截取前8个字符作为生成的随机字符串。
方法2:
# openssl rand -base64 4
f4C+pw==
#这个命令使用openssl命令生成一个长度为4的随机字节流
方法3:
# cat /proc/sys/kernel/random/uuid | cut -c 1-8
c1268803
#只是截取了 UUID 的前8个字符,并不是生成一个随机的8位字符串
获取随机8位数字
方法1:
# echo $RANDOM | cksum |cut -c 1-8
55264714
#这个命令使用$RANDOM变量生成一个随机的整数,并通过cksum命令对其进行校验和计算,然后使用cut命令截取校验和结果的前8个字符作为生成的随机8位数字
方法2:
# openssl rand -base64 4 |cksum |cut -c 1-8
30318431
#这个命令使用openssl rand命令生成一个长度为4的随机字节流,并通过cksum命令对其进行校验和计算,然后使用cut命令截取校验和结果的前8个字符作为生成的随机8位数字
方法3:
# date +%N |cut -c 1-8
94705141
#这个命令使用date命令获取当前时间的纳秒部分,并使用cut命令截取前8个字符作为生成的随机8位数字
方法1:
# 定义一个输出带颜色文本的函数
function echo_color() {
# 判断参数值是否为 "green"
if [ $1 == "green" ]; then
# 使用绿色的前景色输出文本
echo -e "\e[1;32m$2\e[0m"
# 判断参数值是否为 "red"
elif [ $1 == "red" ]; then
# 使用红色的前景色输出文本
echo -e "\033[31m$2\033[0m"
fi
}
方法2:
# 定义一个输出带颜色文本的函数
function echo_color() {
# 根据参数值进行匹配
case $1 in
# 如果参数值为 "green"
green)
# 使用绿色的前景色输出文本
echo -e "\e[1;32m$2\e[0m"
;;
# 如果参数值为 "red"
red)
# 使用红色的前景色输出文本
echo -e "\033[31m$2\033[0m"
;;
*)
# 参数值不在以上两种情况,则输出提示信息
echo "Example: echo_color red string"
esac
}
echo_color green "This is a green text" #这行代码会输出绿色的文本 “This is a green text”。
echo_color red "This is a red text" #这行代码会输出红色的文本 “This is a red text”。
#!/bin/bash
DATE=$(date +%F_%T) # 当前日期和时间,用于备份文件的命名
USER_FILE=user.txt # 用户文件名
# 定义一个输出带颜色文本的函数
echo_color(){
if [ $1 == "green" ]; then
echo -e "\e[1;32m$2\e[0m" # 输出绿色文本
elif [ $1 == "red" ]; then
echo -e "\033[31m$2\033[0m" # 输出红色文本
fi
}
# 如果用户文件存在并且大小大于0就备份
if [ -s $USER_FILE ]; then
mv $USER_FILE ${USER_FILE}-${DATE}.bak # 备份用户文件
echo_color green "$USER_FILE exist, rename ${USER_FILE}-${DATE}.bak" # 输出提示信息,绿色文本
fi
echo -e "User\tPassword" >> $USER_FILE # 在用户文件中添加表头
echo "----------------" >> $USER_FILE # 在用户文件中添加分隔线
# 创建用户,并记录到用户文件中
for USER in user{1..10}; do
if ! id $USER &>/dev/null; then
PASS=$(echo $RANDOM |md5sum |cut -c 1-8) # 生成随机密码
useradd $USER # 创建用户
echo $PASS |passwd --stdin $USER &>/dev/null # 设置用户密码
echo -e "$USER\t$PASS" >> $USER_FILE # 在用户文件中添加用户名和密码
echo "$USER User create successful." # 输出创建用户成功的提示信息
else
echo_color red "$USER User already exists!" # 输出用户已存在的提示信息,红色文本
fi
done
主要流程
#!/bin/bash
# 检查 sysstat 软件包是否已安装
if rpm -q sysstat &>/dev/null; then
echo "sysstat is already installed." # 输出已安装的提示信息
else
echo "sysstat is not installed!" # 输出未安装的提示信息
fi
#!/bin/bash
# 使用 ss 命令查找所有 UDP 连接,并使用 grep 统计包含 "123" 字符串的个数
PORT_C=$(ss -anu | grep -c 123)
# 使用 ps 命令查找所有 ntpd 进程,并使用 grep 过滤掉 grep 进程本身,再统计过滤后的行数
PS_C=$(ps -ef | grep ntpd | grep -vc grep)
# 如果统计到的端口数为 0 或统计到的进程数为 0,则执行下面的操作
if [ $PORT_C -eq 0 -o $PS_C -eq 0 ]; then
# 通过 echo 命令输出邮件内容,然后使用 mail 命令发送邮件给指定的邮箱
echo "内容" | mail -s "主题" [email protected]
fi
方法1:将错误IP放到数组里面判断是否ping失败三次
#!/bin/bash
IP_LIST="192.168.18.1 192.168.1.1 192.168.18.2"
# 循环处理 IP_LIST 中的每个 IP 地址
for IP in $IP_LIST; do
NUM=1 # 用于记录当前重试次数的变量
# 使用 while 循环,最多重试 3 次
while [ $NUM -le 3 ]; do
# 检测指定 IP 地址是否可以通过 ping 命令连通
if ping -c 1 $IP > /dev/null; then
echo "$IP Ping is successful." # 输出提示信息,表示 Ping 成功
break # 跳出当前循环,继续处理下一个 IP 地址
else
# 如果 ping 失败,记录失败次数和相应的 IP 地址
FAIL_COUNT[$NUM]=$IP
let NUM++
fi
done
# 如果连续失败次数达到 3 次,则输出错误信息并清空 FAIL_COUNT 数组
if [ ${#FAIL_COUNT[*]} -eq 3 ];then
echo "${FAIL_COUNT[1]} Ping is failure!" # 输出提示信息,表示 Ping 失败
unset FAIL_COUNT[*] # 清空 FAIL_COUNT 数组的内容
fi
done
方法2:将错误次数放到FAIL_COUNT变量里面判断是否ping失败三次
#!/bin/bash
IP_LIST="192.168.18.1 192.168.1.1 192.168.18.2"
# 循环处理 IP_LIST 中的每个 IP 地址
for IP in $IP_LIST; do
FAIL_COUNT=0 # 用于记录失败次数的变量
# 使用 for 循环尝试最多 3 次 ping 命令
for ((i=1;i<=3;i++)); do
# 检测指定 IP 地址是否可以通过 ping 命令连通
if ping -c 1 $IP >/dev/null; then
echo "$IP Ping is successful." # 输出提示信息,表示 Ping 成功
break # 跳出当前循环,继续处理下一个 IP 地址
else
let FAIL_COUNT++ # 失败次数加 1
fi
done
# 如果连续失败次数达到 3 次,则输出错误信息
if [ $FAIL_COUNT -eq 3 ]; then
echo "$IP Ping is failure!" # 输出提示信息,表示 Ping 失败
fi
done
方法3:利用for循环将ping通就跳出循环继续,如果不跳出就会走到打印ping失败
#!/bin/bash
# 定义函数用于检测 Ping 状态并输出结果
ping_success_status() {
if ping -c 1 $IP >/dev/null; then
echo "$IP Ping is successful." # 输出提示信息,表示 Ping 成功
continue # 继续循环处理下一个 IP 地址
fi
}
IP_LIST="192.168.18.1 192.168.1.1 192.168.18.2"
# 循环处理 IP_LIST 中的每个 IP 地址
for IP in $IP_LIST; do
ping_success_status
ping_success_status
ping_success_status
echo "$IP Ping is failure!" # 输出提示信息,表示 Ping 失败
done
ping_success_status() 函数用于检测指定IP地址的Ping状态并输出结果。
IP_LIST 字符串包含要检测的多个 IP 地址。
使用 for 循环遍历每个 IP 地址,对每个 IP 地址调用 ping_success_status() 函数进行 Ping 测试。
代码的功能:
定义了一个名为 ping_success_status 的函数用于检测 Ping 状态并输出结果。
对于 IP_LIST 中的每个 IP 地址
1)CPU
借助vmstat工具来分析CPU统计信息。
#!/bin/bash
DATE=$(date +%F" "%H:%M) # 获取当前日期和时间
IP=$(ifconfig eth0 | awk -F"[ :]+" '/inet addr/{print $4}') # 获取 eth0 网卡的 IP 地址(在 CentOS 6 中)
MAIL="[email protected]"
# 检查系统是否安装了 vmstat 命令,如果没有找到,则输出错误信息并退出脚本
if ! which vmstat &>/dev/null; then
echo "vmstat command not found. Please install the procps package."
exit 1
fi
# 使用 vmstat 命令获取 CPU 相关的统计数据
US=$(vmstat 1 3 | awk 'NR==5{print $13}') # 用户CPU时间占用百分比
SY=$(vmstat 1 3 | awk 'NR==5{print $14}') # 系统CPU时间占用百分比
IDLE=$(vmstat 1 3 | awk 'NR==5{print $15}') # 空闲CPU时间百分比
WAIT=$(vmstat 1 3 | awk 'NR==5{print $16}') # IO等待百分比
USE=$(($US+$SY)) # 计算用户CPU时间占用和系统CPU时间占用的总和
# 检查 CPU 使用率是否超过阈值(80%),如果超过则发送电子邮件通知
if [ $USE -ge 80 ]; then
echo "
Date: $DATE
Host: $IP
Problem: CPU utilization $USE
" | mail -s "CPU Monitor" $MAIL
fi
代码的功能:
2)内存
#!/bin/bash
DATE=$(date +%F" "%H:%M) # 获取当前日期和时间
IP=$(ifconfig eth0 | awk -F"[ :]+" '/inet addr/{print $4}') # 获取 eth0 网卡的 IP 地址(在 CentOS 6 中)
MAIL="[email protected]"
# 使用 free 命令获取内存相关的统计数据
TOTAL=$(free -m | awk '/Mem/{print $2}') # 内存总量
USE=$(free -m | awk '/Mem/{print $3-$6-$7}') # 已使用的内存量
FREE=$(($TOTAL-$USE)) # 剩余内存量
# 如果剩余内存小于 1G,则发送电子邮件通知
if [ $FREE -lt 1024 ]; then
echo "
Date: $DATE
Host: $IP
Problem: Total=$TOTAL, Use=$USE, Free=$FREE
" | mail -s "Memory Monitor" $MAIL
fi
代码的功能:
前提监控端和被监控端SSH免交互登录或者密钥登录。
写一个配置文件保存被监控主机SSH连接信息,文件内容格式:IP User Port
#!/bin/bash
HOST_INFO=host.info # 主机信息保存的文件路径
rm -f mail.txt # 删除已存在的邮件内容文件
# 遍历主机信息文件中的每个 IP 地址
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
# 从临时文件中提取磁盘利用率信息,并保存到变量 USE_RATE_LIST 中
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#*=} # 获取磁盘利用率部分,即等号(=)右边的值
# 判断磁盘利用率是否超过阈值(80%),如果超过则将警告信息添加到邮件内容文件中
if [ $USE_RATE -ge 80 ]; then
echo "Warning: $PART_NAME Partition usage $USE_RATE%!" >> mail.txt
else
echo "服务器$IP的$PART_NAME目录空间良好"
fi
done
# 发送邮件,将邮件内容文件作为内容,邮件主题为 "空间不足警告"
cat mail.txt | mail -s "空间不足警告" [email protected]
done
代码的功能:
1)检查URL可用性
# 方法1:使用 curl 命令检查 URL 的访问状态
check_url() {
HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%{http_code}" $1)
# 使用 curl 命令测试 HTTP 头以检查 URL 的访问状态,超时时间为 3 秒,并将 HTTP 状态码保存到变量 HTTP_CODE 中
if [ $HTTP_CODE -ne 200 ]; then
echo "Warning: $1 Access failure!"
# 如果 HTTP 状态码不等于 200(即不成功),则输出警告信息,表示 URL 访问失败
fi
}
# 方法2:使用 wget 命令检查 URL 的访问状态
check_url() {
if ! wget -T 10 --tries=1 --spider $1 >/dev/null 2>&1; then
# 使用 wget 命令以爬虫模式检查 URL 的访问状态,超时时间为 10 秒,并尝试访问 1 次,将输出重定向到 /dev/null,将错误输出重定向到标准输出并丢弃
echo "Warning: $1 Access failure!"
# 如果 wget 命令返回非零退出码,则输出警告信息,表示 URL 访问失败
fi
}
代码的功能:
2)判断三次URL可用性
方法1:利用循环技巧,如果成功就跳出当前循环,否则执行到最后一行
#!/bin/bash
# 检查URL的访问状态
check_url() {
HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%{http_code}" $1)
# 使用 curl 命令测试 HTTP 头以检查 URL 的访问状态,超时时间为 3 秒,并将 HTTP 状态码保存到变量 HTTP_CODE 中
if [ $HTTP_CODE -eq 200 ]; then
continue
# 如果 HTTP 状态码等于 200(即成功),则继续循环,不执行后续操作
fi
}
URL_LIST="www.baidu.com www.agasgf.com"
# 存储待检查的 URL 列表
for URL in $URL_LIST; do
check_url $URL
# 依次遍历 URL 列表,调用 check_url 函数检查每个 URL 的访问状态
# 如果返回的 HTTP 状态码等于 200,则继续循环,不执行后续操作
check_url $URL
check_url $URL
# 连续调用 check_url 函数,最多尝试三次
echo "Warning: $URL Access failure!"
# 输出警告信息,表示 URL 访问失败
done
代码的功能:
方法2:错误次数保存到变量
#!/bin/bash
URL_LIST="www.baidu.com www.agasgf.com"
# 存储待检查的 URL 列表
for URL in $URL_LIST; do
FAIL_COUNT=0
# 用于统计 URL 访问失败的次数的变量
for ((i=1;i<=3;i++)); do
# 进行最多三次的访问尝试
HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%{http_code}" $URL)
# 使用 curl 命令测试 HTTP 头以检查 URL 的访问状态,超时时间为 3 秒,并将 HTTP 状态码保存到变量 HTTP_CODE 中
if [ $HTTP_CODE -ne 200 ]; then
let FAIL_COUNT++
# 如果 HTTP 状态码不等于 200(即访问失败),则将失败次数加一
else
break
# 如果 HTTP 状态码等于 200(即访问成功),则跳出循环,不执行后续尝试
fi
done
if [ $FAIL_COUNT -eq 3 ]; then
echo "Warning: $URL Access failure!"
# 如果 URL 访问失败的次数等于 3,即尝试了三次都失败,则输出警告信息,表示 URL 访问失败
fi
done
代码的功能:
方法3:错误次数保存到数组
#!/bin/bash
URL_LIST="www.baidu.com www.agasgf.com"
# 存储待检查的 URL 列表
for URL in $URL_LIST; do
NUM=1
# 用于计数的变量 NUM,初始值为 1
while [ $NUM -le 3 ]; do
# 进行最多三次的访问尝试
HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%{http_code}" $URL)
# 使用 curl 命令测试 HTTP 头以检查 URL 的访问状态,超时时间为 3 秒,并将 HTTP 状态码保存到变量 HTTP_CODE 中
if [ $HTTP_CODE -ne 200 ]; then
FAIL_COUNT[$NUM]=$IP
# 如果 HTTP 状态码不等于 200(即访问失败),则将失败的 URL 存储到数组 FAIL_COUNT 中,以 NUM 作为下标,IP 作为元素
let NUM++
# 数量加一,进行下一次尝试
else
break
# 如果 HTTP 状态码等于 200(即访问成功),则跳出循环,不再进行尝试
fi
done
if [ ${#FAIL_COUNT[*]} -eq 3 ]; then
echo "Warning: $URL Access failure!"
unset FAIL_COUNT[*]
# 如果 FAIL_COUNT 数组中有三个元素,即进行了三次尝试都失败,则输出警告信息,表示 URL 访问失败,并清空 FAIL_COUNT 数组
fi
done
代码的功能:
#!/bin/bash
USER=bak
PASSWD=123456
IO_SQL_STATUS=$(mysql -u$USER -p$PASSWD -e show slave statusG | awk -F: /Slave_.*_Running/{gsub(": ",":");print $0})
# 执行 mysql 命令获取 MySQL 主从状态,并使用 awk 命令根据关键字 "Slave_.*_Running" 解析出对应的行,并去除冒号后的空格
for i in $IO_SQL_STATUS; do
THREAD_STATUS_NAME=${i%:*}
# 通过 %:* 取 THREAD_STATUS_NAME 字符串变量,获取冒号前的部分
THREAD_STATUS=${i#*:}
# 通过 #*: 取 THREAD_STATUS 字符串变量,获取冒号后的部分
if [ "$THREAD_STATUS" != "Yes" ]; then
echo "Error: MySQL Master-Slave $THREAD_STATUS_NAME status is $THREAD_STATUS!"
# 如果 THREAD_STATUS 不等于 "Yes",则输出错误信息,表示 MySQL 主从状态异常
fi
done
代码的功能:
场景:恶意访问,安全防范
1)屏蔽每分钟访问超过200的IP
方法1:根据访问日志(Nginx为例)
#!/bin/bash
DATE=$(date +%d/%b/%Y:%H:%M)
# 获取当前日期和时间,并格式化为 "%d/%b/%Y:%H:%M" 的形式,赋值给变量 DATE
ABNORMAL_IP=$(tail -n 5000 access.log | grep $DATE | awk '{a[$1]++}END{for(key in a)if(a[key]>100)print key}')
# 使用 tail 命令读取文件 access.log 的最后 5000 行日志,然后通过 grep 过滤出包含当前日期的行,最后使用 awk 命令统计 IP 地址出现的次数,如果次数大于 100,则将 IP 地址打印出来,赋值给变量 ABNORMAL_IP
for IP in $ABNORMAL_IP; do
# 使用 for 循环遍历 ABNORMAL_IP 中的每个 IP 地址
if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then
# 使用 iptables 命令查看当前防火墙规则,并使用 grep 过滤出包含指定 IP 地址的行,并使用 -c 参数统计匹配行的数量
# 如果匹配行的数量等于 0,表示当前 IP 地址不在防火墙规则中
iptables -I INPUT -s $IP -j DROP
# 在 INPUT 链的开头插入一条规则,拒绝指定 IP 地址的所有输入流量
fi
done
这段代码的功能是根据 access.log 中的日志数据,检测发起请求次数超过设定阈值的 IP 地址,并将这些 IP 地址加入防火墙规则,拒绝其输入流量。
代码的功能:
方法2:通过TCP建立的连接
#!/bin/bash
ABNORMAL_IP=$(netstat -an | awk '$4~/:80$/ && $6~/ESTABLISHED/{gsub(/:[0-9]+/,"",$5);{a[$5]++}}END{for(key in a)if(a[key]>100)print key}')
# 使用 netstat 命令获取网络连接状态,通过 awk 过滤出本地端口为 80 的已建立连接(ESTABLISHED)的行,并使用 gsub 函数去除客户端 IP 地址中的冒号和端口号,然后统计每个 IP 地址的出现次数,如果次数大于 100,则将 IP 地址打印出来,赋值给变量 ABNORMAL_IP
for IP in $ABNORMAL_IP; do
# 使用 for 循环遍历 ABNORMAL_IP 中的每个 IP 地址
if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then
# 使用 iptables 命令查看当前防火墙规则,并使用 grep 过滤出包含指定 IP 地址的行,并使用 -c 参数统计匹配行的数量
# 如果匹配行的数量等于 0,表示当前 IP 地址不在防火墙规则中
iptables -I INPUT -s $IP -j DROP
# 在 INPUT 链的开头插入一条规则,拒绝指定 IP 地址的所有输入流量
fi
done
这段代码的功能是通过 netstat 命令检测当前与本地端口 80 建立的连接,并统计每个客户端 IP 地址的连接次数,如果连接次数超过设定阈值,就将对应 IP 地址加入防火墙规则。
代码的功能:
2)屏蔽每分钟SSH尝试登录超过10次的IP
方法1:通过lastb获取登录状态
#!/bin/bash
DATE=$(date +"%a %b %e %H:%M")
# 获取当前日期和时间,并使用格式化字符串 "%a %b %e %H:%M" 赋值给变量 DATE
# %a: 星期几的缩写(例如:Mon、Tue)
# %b: 月份的缩写(例如:Jan、Feb)
# %e: 月份中的天数(仅用一个数字表示,如:7)
# %H: 小时(24小时制)
# %M: 分钟
ABNORMAL_IP=$(lastb | grep "$DATE" | awk '{a[$3]++}END{for(key in a)if(a[key]>10)print key}')
# 使用 lastb 命令获取登录失败的记录,通过 grep 过滤出包含当前日期的行,然后使用 awk 命令统计每个 IP 地址出现的次数,如果次数大于 10,则将 IP 地址打印出来,赋值给变量 ABNORMAL_IP
for IP in $ABNORMAL_IP; do
# 使用 for 循环遍历 ABNORMAL_IP 中的每个 IP 地址
if [ $(iptables -vnL | grep -c "$IP") -eq 0 ]; then
# 使用 iptables 命令查看当前防火墙规则,并使用 grep 过滤出包含指定 IP 地址的行,并使用 -c 参数统计匹配行的数量
# 如果匹配行的数量等于 0,表示当前 IP 地址不在防火墙规则中
iptables -I INPUT -s $IP -j DROP
# 在 INPUT 链的开头插入一条规则,拒绝指定 IP 地址的所有输入流量
fi
done
这段代码的功能是检测最近登录失败的记录(使用 lastb 命令),并统计每个 IP 地址的登录失败次数。如果登录失败次数超过设定阈值,就将对应 IP 地址加入防火墙规则,禁止其输入流量。
代码的功能:
方法2:通过日志获取登录状态
#!/bin/bash
DATE=$(date +"%b %d %H")
# 获取当前日期和时间,并使用格式化字符串 "%b %d %H" 格式化成月份、日期、小时的形式,赋值给变量 DATE
# %b: 月份的缩写(例如:Jan、Feb)
# %d: 月份中的天数(例如:07)
# %H: 小时(24小时制)
ABNORMAL_IP="$(tail -n10000 /var/log/auth.log | grep "$DATE" | awk '/Failed/{a[$(NF-3)]++}END{for(key in a)if(a[key]>5)print key}')"
# 使用 tail 命令读取文件 /var/log/auth.log 的最后10000行日志
# 通过 grep 过滤出包含当前日期的行
# 使用 awk 命令找出包含 "Failed" 关键词的行,并以行中倒数第 3 个字段(即 IP 地址)为 key,统计出现次数
# 如果次数大于 5,则将 IP 地址打印出来,赋值给变量 ABNORMAL_IP
for IP in $ABNORMAL_IP; do
# 使用 for 循环遍历 ABNORMAL_IP 中的每个 IP 地址
if [ $(iptables -vnL | grep -c "$IP") -eq 0 ]; then
# 使用 iptables 命令查看当前防火墙规则,并使用 grep 过滤出包含指定 IP 地址的行,并使用 -c 参数统计匹配行的数量
# 如果匹配行的数量等于 0,表示当前 IP 地址不在防火墙规则中
iptables -A INPUT -s $IP -j DROP
# 在 INPUT 链的末尾追加一条规则,拒绝指定 IP 地址的所有输入流量
echo "$(date +"%F %T") - iptables -A INPUT -s $IP -j DROP" >> ~/ssh-login-limit.log
# 将执行的 iptables 命令和时间记录到 ~/ssh-login-limit.log 日志文件中
fi
done
这段代码的功能是检测 /var/log/auth.log 文件中最近出现的登录失败记录,并统计每个 IP 地址的登录失败次数。如果登录失败次数超过设定阈值,就将对应 IP 地址加入防火墙规则,禁止其输入流量,并将执行的 iptables 命令和时间记录到 ~/ssh-login-limit.log 日志文件中。
代码的功能:
方法1:
#!/bin/bash
# 定义函数 check_ip,用于检查输入的 IP 地址是否合法
function check_ip(){
local IP=$1
VALID_CHECK=$(echo $IP | awk -F"." '{if($1<=255&&$2<=255&&$3<=255&&$4<=255) print "yes"; else print "no"}')
# 将 IP 地址按照 "." 分隔成四个字段,并使用 awk 判断每个字段的取值范围是否合法(0-255)
if echo $IP | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" > /dev/null; then
# 使用正则表达式验证 IP 地址的格式,必须为 1-3 位数字 + "." + 1-3 位数字 + "." + 1-3 位数字 + "." + 1-3 位数字
# 将匹配结果重定向到 /dev/null,即丢弃匹配结果
if [[ "$VALID_CHECK" == "yes" ]]; then
echo "$IP available."
return 0
else
echo "$IP not available!"
return 1
fi
else
echo "Format error!"
return 1
fi
}
while true; do
read -p "Please enter IP: " ip
# 提示用户输入 IP 地址,并将输入保存到变量 ip 中
check_ip $ip
# 调用函数 check_ip,传入用户输入的 IP 地址作为参数进行检查
# 如果函数返回值为 0,表示 IP 地址合法,跳出循环
# 如果函数返回值为 1,表示 IP 地址不合法,继续循环
done
这段代码实现了一个循环,提示用户输入 IP 地址,并通过调用函数 check_ip 对输入的 IP 地址进行检查,直到用户输入合法的 IP 地址为止。
代码的功能:
方法2:
#!/bin/bash
# 定义函数 check_ip,用于检查输入的 IP 地址是否合法
function check_ip(){
IP=$1
if [[ $IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
# 使用正则表达式验证 IP 地址的格式,必须为 1-3 位数字 + "." + 1-3 位数字 + "." + 1-3 位数字 + "." + 1-3 位数字
FIELD1=$(echo $IP|cut -d. -f1)
FIELD2=$(echo $IP|cut -d. -f2)
FIELD3=$(echo $IP|cut -d. -f3)
FIELD4=$(echo $IP|cut -d. -f4)
# 使用 cut 命令按照 "." 分割 IP 地址,并分别将每个字段赋值给对应的变量
if [ $FIELD1 -le 255 -a $FIELD2 -le 255 -a $FIELD3 -le 255 -a $FIELD4 -le 255 ]; then
# 判断每个字段的取值是否都小于等于 255
echo "$IP available."
# 输出 IP 地址合法
else
echo "$IP not available!"
# 输出 IP 地址不合法,至少有一个字段的取值大于 255
fi
else
echo "Format error!"
# 输出 IP 地址格式错误
fi
}
check_ip 192.168.1.1
# 调用 check_ip 函数,传入参数 192.168.1.1 进行检查
check_ip 256.1.1.1
# 调用 check_ip 函数,传入参数 256.1.1.1 进行检查
这段代码定义了一个函数 check_ip,用于检查输入的 IP 地址是否合法,并对两个 IP 地址进行了检查。
代码的功能:
在主程序中,调用 check_ip 函数进行两次检查:
方法1:
#!/bin/bash
# 使用正则表达式判断参数是否为数字
if [[ $1 =~ ^[0-9]+$ ]]; then
echo "Is Number."
# 如果参数是由一个或多个数字组成,输出 "Is Number."
else
echo "No Number."
# 如果参数不是由一个或多个数字组成,输出 "No Number."
fi
段代码使用正则表达式判断参数是否为数字。
代码的功能:
方法2:
#!/bin/bash
# 判断参数是否为一个数字
if [ $1 -gt 0 ] 2>/dev/null; then
echo "Is Number."
# 如果参数大于 0,即参数是一个数字,输出 "Is Number."
else
echo "No Number."
# 如果参数不是一个数字,输出 "No Number."
fi
这段代码使用条件判断语句判断参数是否为一个数字。
代码的功能:
方法3:
#!/bin/bash
echo $1 | awk '{print $0~/^[0-9]+$/?"Is Number.":"No Number."}'
# 使用 awk 命令打印判断结果,使用三元运算符进行条件判断
# 解释:
# - `echo $1` 打印第一个参数
# - `awk` 命令用于处理文本数据
# - `{print $0~/^[0-9]+$/?"Is Number.":"No Number."}` 是 awk 的脚本部分,用于判断参数是否为一个数字并进行打印
# - `$0` 表示当前行的文本内容,即传入的参数
# - `~` 是 awk 的匹配操作符
# - `/^[0-9]+$/` 是正则表达式,用于匹配一个或多个数字的字符串
# - `?` 是三元运算符的条件部分,即判断参数是否匹配正则表达式
# - 如果参数匹配正则表达式,返回 "Is Number.",否则返回 "No Number."
这段代码使用了 awk 命令和三元运算符来判断参数是否是一个数字,并进行相应的输出。
#!/bin/bash
DIR=$1 # 存储目录路径
KEY=$2 # 存储要搜索的关键词
# 使用循环逐个遍历目录下的文件
for FILE in $(find $DIR -type f); do
# 在文件中搜索关键词,并将输出重定向到 `/dev/null`,即丢弃匹配结果
if grep $KEY $FILE &>/dev/null; then
echo "--> $FILE"
# 如果搜索到关键词,输出文件路径
fi
done
这段代码的功能是在给定的目录中搜索包含指定关键词的文件,并输出文件的路径。
代码的功能:
场景:记录目录下文件操作。
需先安装inotify-tools软件包。
-m #持续监听
-r #使用递归形式监控目录
-q #减少冗余信息,只打印出需要的信息
-e #指定要监控的事件,多个事件使用逗号隔开
access #访问,读取文件
modify #修改,文件内容被修改
attrib #属性,文件元数据被修改
move #移动,对文件进行移动操作 move_to move_from
create #创建,生成新文件
open #打开,对文件进行打开操作
close #关闭,对文件进行关闭操作 close_write close_nowrite
delete #删除,文件被删除 delete_self
unmount #卸载文件或目录的文件系统
--timefmt #时间格式 y 年 m月 d日 H小时 M分钟
--format #监控事件发生后的信息输出格式
%w #表示发生事件的目录
%f #表示发生事件的文件
%e #表示发生的事件
%Xe #事件以“X”分隔
%T #使用由 --timefmt定义的时间格式
--exclude #排除文件或目录时,大小写敏感
# --exclude="(.*.swp)|(.*~$)|(.*.swx)"使用正则匹配排除文件
# inotifywait + rsync 同步,放在后台跑
#!/bin/bash
MON_DIR=/tmp # 要监视的目录
# 使用 inotifywait 监视 $MON_DIR 目录中的文件创建事件,并输出文件名
inotifywait -mq --format %f -e create $MON_DIR | \
while read files; do
# 对每个文件执行 rsync 命令
echo rsync -avz $files admin@ip:/tmp
done
这段代码的功能是使用 inotifywait 监视指定目录中的文件创建事件,并在有文件创建时执行 rsync 命令。
代码的功能:
场景:服务器多个网卡时,获取指定网卡,例如网卡流量
#!/bin/bash
function local_nic() {
local NUM ARRAY_LENGTH
NUM=0
for NIC_NAME in $(ls /sys/class/net | grep -vE "lo|docker0"); do
NIC_IP=$(ifconfig $NIC_NAME | awk -F'[: ]+' '/inet addr/{print $4}')
if [ -n "$NIC_IP" ]; then
NIC_IP_ARRAY[$NUM]="$NIC_NAME:$NIC_IP"
# 将网卡名和对应IP放到数组
let NUM++
fi
done
ARRAY_LENGTH=${#NIC_IP_ARRAY[*]}
# 获取数组长度
if [ $ARRAY_LENGTH -eq 1 ]; then
# 如果数组里面只有一条记录,说明只有一个网卡
NIC=${NIC_IP_ARRAY[0]%:*}
# 获取网卡名称(去除IP地址部分)
return 0
elif [ $ARRAY_LENGTH -eq 0 ]; then
# 如果没有记录,说明没有可用的网卡
echo "No available network card!"
exit 1
else
# 如果有多条记录,则提醒输入选择
for NIC in ${NIC_IP_ARRAY[*]}; do
echo $NIC
# 输出所有网卡名称和对应的IP地址
done
while true; do
read -p "Please enter the name of the network card to use: " INPUT_NIC_NAME
# 提示用户输入要使用的网卡名称
COUNT=0
for NIC in ${NIC_IP_ARRAY[*]}; do
NIC_NAME=${NIC%:*}
if [ $NIC_NAME == "$INPUT_NIC_NAME" ]; then
NIC=${NIC_IP_ARRAY[$COUNT]%:*}
# 获取用户输入网卡名称对应的IP地址
return 0
else
COUNT+=1
fi
done
echo "Not match! Please input again."
# 如果输入不匹配,要求用户重新输入
done
fi
}
local_nic
这段代码的功能是获取本地可用的网卡和对应的IP地址,并要求用户选择要使用的网卡。
代码的功能:
适用于CentOS操作系统。
#!/bin/bash
# Description: Only CentOS
# traffic_unit_conv函数将流量转换为合适的单位(KB/s或MB/s)
traffic_unit_conv() {
local traffic=$1
if [ $traffic -gt 1024000 ]; then
printf "%.1f%s" "$(($traffic/1024/1024))" "MB/s"
# 如果流量大于1024000(1024KB),将流量转换为MB/s并保留1位小数
elif [ $traffic -lt 1024000 ]; then
printf "%.1f%s" "$(($traffic/1024))" "KB/s"
# 如果流量小于1024000(1024KB),将流量转换为KB/s并保留1位小数
fi
}
NIC=$1 # 获取用户传入的参数作为要监测的网卡名称
echo -e " In ------ Out"
# 打印标题 "In ------ Out"
while true; do
# 进入无限循环,监测流量变化
OLD_IN=$(awk -F'[: ]+' '$0~"'$NIC'"{print $3}' /proc/net/dev)
# 获取旧的接收流量(使用awk命令从/proc/net/dev中提取)
OLD_OUT=$(awk -F'[: ]+' '$0~"'$NIC'"{print $11}' /proc/net/dev)
# 获取旧的发送流量(使用awk命令从/proc/net/dev中提取)
sleep 1
# 等待1秒,以便获取新的流量数据
NEW_IN=$(awk -F'[: ]+' '$0~"'$NIC'"{print $3}' /proc/net/dev)
# 获取新的接收流量
NEW_OUT=$(awk -F'[: ]+' '$0~"'$NIC'"{print $11}' /proc/net/dev)
# 获取新的发送流量
IN=$(($NEW_IN-$OLD_IN))
# 计算接收的流量差值
OUT=$(($NEW_OUT-$OLD_OUT))
# 计算发送的流量差值
echo "$(traffic_unit_conv $IN) $(traffic_unit_conv $OUT)"
# 调用traffic_unit_conv函数将流量差值转换为合适的单位并打印
sleep 1
# 等待1秒,以便下一次获取流量数据
done
# 结束循环
这段代码的功能是监测指定网卡的接收和发送流量,并每秒打印一次流量值。
代码的功能:
使用:./traffic.sh eth0
#!/bin/bash
DATE=$(date +%F_%H-%M-%S) # 获取当前日期和时间,用于备份文件名
HOST=192.168.1.120 # 数据库主机地址
DB=test # 数据库名称
USER=bak # 数据库用户名
PASS=123456 # 数据库密码
MAIL="[email protected] [email protected]" # 接收备份结果通知的邮件地址
BACKUP_DIR=/data/db_backup # 备份文件存储路径
SQL_FILE=${DB}_full_$DATE.sql # 生成的 SQL 备份文件名
BAK_FILE=${DB}_full_$DATE.zip # 生成的压缩备份文件名
cd $BACKUP_DIR # 切换到备份文件存储路径
# 使用 mysqldump 命令备份数据库,并将结果输出到 SQL 备份文件中
if mysqldump -h$HOST -u$USER -p$PASS --single-transaction --routines --triggers -B $DB > $SQL_FILE; then
# 如果备份成功,则将 SQL 备份文件压缩为压缩备份文件,并删除原始 SQL 备份文件
zip $BAK_FILE $SQL_FILE && rm -f $SQL_FILE
# 如果压缩备份文件为空,则表示备份数据可能出错,发送邮件通知
if [ ! -s $BAK_FILE ]; then
echo "$DATE 内容" | mail -s "主题" $MAIL
fi
else
# 如果备份失败,发送邮件通知
echo "$DATE 内容" | mail -s "主题" $MAIL
fi
# 删除14天前的压缩备份文件
find $BACKUP_DIR -name '*.zip' -ctime +14 -exec rm {} \;
这段代码的功能是备份指定数据库,并将备份文件压缩,最后删除过期的备份文件。
代码的功能:
场景:使用源码包安装Nginx不含带服务管理脚本,也就是不能使用"service nginx start"或"/etc/init.d/nginx start",所以写了以下的服务管理脚本。
#!/bin/bash
# Description: Only support RedHat system
. /etc/init.d/functions
WORD_DIR=/usr/local/nginx # Nginx安装目录
DAEMON=$WORD_DIR/sbin/nginx # Nginx可执行文件路径
CONF=$WORD_DIR/conf/nginx.conf # Nginx配置文件路径
NAME=nginx # 进程名称
PID=$(awk -F'[; ]+' '/^[^#]/{if($0~/pid;/)print $2}' $CONF) # 获取配置文件中定义的PID文件路径
# 如果配置文件中未定义PID文件路径,设置默认的PID文件路径
if [ -z "$PID" ]; then
PID=$WORD_DIR/logs/nginx.pid
else
PID=$WORD_DIR/$PID
fi
stop() {
$DAEMON -s stop # 发送信号停止Nginx进程
sleep 1
# 判断PID文件是否存在,根据结果输出不同的操作提示
[ ! -f $PID ] && action "* Stopping $NAME" /bin/true || action "* Stopping $NAME" /bin/false
}
start() {
$DAEMON # 启动Nginx进程
sleep 1
# 判断PID文件是否存在,根据结果输出不同的操作提示
[ -f $PID ] && action "* Starting $NAME" /bin/true || action "* Starting $NAME" /bin/false
}
reload() {
$DAEMON -s reload # 发送信号重新加载Nginx配置
}
test_config() {
$DAEMON -t # 检查Nginx配置文件语法是否正确
}
case "$1" in
start)
# 如果PID文件不存在,启动Nginx进程;否则输出进程正在运行的提示
if [ ! -f $PID ]; then
start
else
echo "$NAME is running..."
exit 0
fi
;;
stop)
# 如果PID文件存在,停止Nginx进程;否则输出进程未运行的提示
if [ -f $PID ]; then
stop
else
echo "$NAME not running!"
exit 0
fi
;;
restart)
# 如果PID文件不存在,输出进程未运行的提示并启动Nginx进程;否则先停止再启动
if [ ! -f $PID ]; then
echo "$NAME not running!"
start
else
stop
start
fi
;;
reload)
# 发送信号重新加载Nginx配置
reload
;;
testconfig)
# 检查Nginx配置文件语法是否正确
test_config
;;
status)
# 根据PID文件是否存在输出不同的状态提示
[ -f $PID ] && echo "$NAME is running..." || echo "$NAME not running!"
;;
*)
# 输出脚本的使用方法,并退出脚本(返回退出码3)
echo "Usage: $0 {start|stop|restart|reload|testconfig|status}"
exit 3
;;
esac
这段脚本实现了对 Nginx 服务的启停、重启、重新加载配置文件以及检查配置文件语法的功能。
代码的功能:
Linux主机SSH连接信息:
# cat host.txt
Web 192.168.1.10 root 22
DB 192.168.1.11 root 22
内容格式:主机名 IP User Port
#!/bin/bash
PS3="Please input number: " # 设置 select 命令的提示信息
HOST_FILE=host.txt # 存储主机连接信息的文件路径
# 无限循环,用于不断提供主机选择菜单
while true; do
# 使用 select 命令选择主机名(从 host.txt 文件中获取)
select NAME in $(awk '{print $1}' $HOST_FILE) quit; do
# 如果选择的主机名为 "quit",退出脚本
[ ${NAME:=empty} == "quit" ] && exit 0
# 根据选择的主机名从 host.txt 文件中获取对应的 IP、用户名和端口号
IP=$(awk -v NAME=${NAME} '$1==NAME{print $2}' $HOST_FILE)
USER=$(awk -v NAME=${NAME} '$1==NAME{print $3}' $HOST_FILE)
PORT=$(awk -v NAME=${NAME} '$1==NAME{print $4}' $HOST_FILE)
if [ $IP ]; then
echo "Name: $NAME, IP: $IP"
# 使用 ssh 命令连接远程主机,使用密钥免交互登录
ssh -o StrictHostKeyChecking=no -p $PORT -i id_rsa $USER@$IP
break
else
echo "Input error, Please enter again!"
break
fi
done
done
这段脚本实现了根据主机名从 host.txt 文件中获取主机的连接信息,并使用 SSH 命令连接远程主机的功能。
代码的功能:
#!/bin/bash
# 检查参数数量是否为1
if [ $# -ne 1 ]; then
echo "Usage: $0 filename"
fi
# 获取指定文件的目录和文件名
dir=$(dirname $1)
file=$(basename $1)
# 使用 ftp 命令连接 FTP 服务器并执行操作
ftp -n -v << EOF # -n 自动登录
open 192.168.1.10 # ftp服务器
user admin password # 使用指定的用户名和密码登录
binary # 设置ftp传输模式为二进制,避免MD5值不同或.tar.gz压缩包格式错误
cd $dir # 切换到指定的目录
get "$file" # 下载指定的文件
EOF
这段脚本实现了通过 FTP 下载指定文件的功能。
代码的功能:
#!/bin/bash
# 初始化计数器、和、最小值、最大值
COUNT=1
SUM=0
MIN=0
MAX=100
# 循环5次,读取用户输入的整数并进行相关操作
while [ $COUNT -le 5 ]; do
read -p "请输入1-10个整数:" INT # 提示用户输入1-10个整数
if [[ ! $INT =~ ^[0-9]+$ ]]; then # 判断输入是否为整数
echo "输入必须是整数!"
exit 1 # 若输入不是整数,退出脚本,返回退出码 1
elif [[ $INT -gt 100 ]]; then # 判断输入是否小于等于100
echo "输入必须是100以内!"
exit 1 # 若输入大于100,退出脚本,返回退出码 1
fi
SUM=$(($SUM+$INT)) # 累加输入的整数到和变量
[ $MIN -lt $INT ] && MIN=$INT # 更新最小值变量
[ $MAX -gt $INT ] && MAX=$INT # 更新最大值变量
let COUNT++ # 计数器自增
done
# 输出计算结果
echo "SUM: $SUM" # 输出和
echo "MIN: $MIN" # 输出最小值
echo "MAX: $MAX" # 输出最大值
这段脚本实现了读取用户输入的整数,计算输入的整数的和、最小值和最大值,并输出结果。
代码的功能:
应用场景:希望将执行结果或者位置参数赋值给变量,以便后续使用。
方法1:
for i in $(echo "4 5 6"); do # 循环遍历 "4 5 6"
eval a$i=$i # 为变量 a4、a5、a6 赋值,变量名由 $i 决定,值为 $i 的值
done
echo $a4 $a5 $a6 # 输出变量 a4、a5、a6 的值
# 这段代码的目的是创建变量 a4、a5、a6,并将其赋值为 4、5、6
这段代码使用 for 循环遍历列表 “4 5 6”,对于每个列表中的元素,使用 eval 命令动态创建变量 a4、a5、a6,并赋值为相应的值。最后通过 echo 命令输出变量 a4、a5、a6 的值。
方法2:将位置参数192.168.1.1{1,2}拆分为到每个变量
num=0 # 初始化计数器变量为0
for i in $(eval echo $*); do # 循环遍历命令行参数,并使用 eval 命令展开参数中的花括号拓展表达式
let num+=1 # 计数器自增
eval node${num}="$i" # 动态创建变量 node1、node2、node3,并赋值为相应的参数值
done
echo $node1 $node2 $node3 # 输出变量 node1、node2、node3 的值
# 示例运行命令:bash a.sh 192.168.1.1{1,2}
# 输出:192.168.1.11 192.168.1.12
# 这段代码的目的是根据命令行参数动态创建变量,并赋予相应的值
这段代码通过 for 循环遍历命令行参数(使用 $* 获取所有参数),使用 eval 命令将参数中的花括号拓展表达式展开(如 192.168.1.1{1,2} 拓展为 192.168.1.11 192.168.1.12),然后在循环中,计数器 num 自增,然后使用 eval 命令动态创建变量 node1、node2、node3,并赋值为相应的参数值。最后通过 echo 命令输出变量 node1、node2、node3 的值。
方法3:
arr=(4 5 6) # 创建包含元素 4、5、6 的数组 arr
INDEX1=$(echo ${arr[0]}) # 获取数组 arr 中的第一个元素,并将其赋值给变量 INDEX1
INDEX2=$(echo ${arr[1]}) # 获取数组 arr 中的第二个元素,并将其赋值给变量 INDEX2
INDEX3=$(echo ${arr[2]}) # 获取数组 arr 中的第三个元素,并将其赋值给变量 INDEX3
# 这段代码的目的是从数组 arr 中提取元素,并赋值给相应的变量
这段代码创建了一个名为 arr 的数组,其中包含了元素 4、5、6。
然后,使用 ${arr[index]} 的形式从数组 arr 中提取特定索引位置的元素,并使用 echo 命令将其输出。通过将提取的元素赋值给相应的变量(INDEX1、INDEX2、INDEX3),来存储和使用这些值。
通过这种方式,变量 INDEX1、INDEX2 和 INDEX3 将分别包含数组 arr 中对应索引位置的值。
示例:
# touch article_{1..3}.html
# ls
article_1.html article_2.html article_3.html
目的:把article改为bbs
方法1:
for file in $(ls *html); do # 循环遍历当前目录下以 html 结尾的文件
mv $file bbs_${file#*_} # 将文件名修改为 bbs_ 后加上原文件名中第一个下划线后的部分
# 同等效果的替代方法1:
# mv $file $(echo $file |sed -r 's/.*(_.*)/bbs\1/')
# 同等效果的替代方法2:
# mv $file $(echo $file |echo bbs_$(cut -d_ -f2)
done
这段代码的作用是遍历当前目录下以 .html 结尾的文件,并将文件名进行修改。
替代方法1:mv $file $(echo $file |sed -r 's/*(_.* )/bbs\1/'),使用 sed 命令进行正则表达式的替换操作,将文件名中的第一个下划线及其后的部分替换为 bbs_ 加上对应的部分。
替代方法2:mv $ file $ (echo $ file |echo bbs_$(cut -d_ -f2),使用 cut 命令提取文件名中第一个下划线后的部分,然后将其拼接为 bbs_ 加上对应的部分。
这段代码的目的是对当前目录下以 .html 结尾的文件进行批量重命名,将文件名修改为以 bbs_ 开头并保留原文件名中第一个下划线后的部分。
方法2:
for file in $(find . -maxdepth 1 -name "*html"); do # 使用 find 命令查找当前目录下的以 html 结尾的文件
mv $file bbs_${file#*_} # 将文件名修改为 bbs_ 后加上原文件名中第一个下划线后的部分
done
这段代码的作用是在当前目录下查找以 .html 结尾的文件,并将这些文件的文件名进行修改。
这段代码的目的是在当前目录下查找以 .html 结尾的文件,并将这些文件的文件名批量修改为以 bbs_ 开头并保留原文件名中第一个下划线后的部分。
方法3:
# rename article bbs *.html
这段代码使用了 rename 命令,对当前目录下以 .html 结尾的文件进行批量重命名。
这段代码的目的是将当前目录下以 .html 结尾的文件名中的 article 替换为 bbs,实现文件名的批量重命名操作。
方法1:
# find . -name "*.html" -exec du -k {} \; |awk '{sum+=$1}END{print sum}'
这段代码使用了find命令、du命令和awk命令来计算当前目录下以.html结尾的文件的总大小(以KB为单位)。
这段代码的目的是计算当前目录下以.html结尾的文件的总大小(以KB为单位)。
方法2:
for size in $(ls -l *.html | awk '{print $5}'); do # 获取当前目录下以 .html 结尾的文件的大小列表
sum=$(($sum+$size)) # 对每个文件的大小进行累加
done
echo $sum # 打印所有文件大小的总和
这段代码的作用是计算当前目录下以 .html 结尾的文件的总大小(以字节为单位)。
这段代码的目的是计算当前目录下以 .html 结尾的文件的总大小(以字节为单位),将每个文件的大小累加到变量 sum 中,并最后打印出总和。
#!/bin/bash
HOST=$1 # 获取第一个命令行参数,作为主机名或 IP 地址
PORT="22 25 80 8080" # 定义要检测的端口列表
for PORT in $PORT; do # 遍历端口列表
if echo &>/dev/null > /dev/tcp/$HOST/$PORT; then # 使用 /dev/tcp 文件系统,尝试与指定的主机和端口建立 TCP 连接
echo "$PORT open" # 如果 TCP 连接成功,则输出端口为开放状态
else
echo "$PORT close" # 如果 TCP 连接失败,则输出端口为关闭状态
fi
done
这段代码的作用是检测指定主机的一些常见端口是否开放。
这段代码的目的是遍历指定主机的端口列表,并尝试与每个端口建立 TCP 连接,通过输出端口状态来告知该端口是否开放。
Expect是一个自动交互式应用程序的工具,如telnet,ftp,passwd等。
需先安装expect软件包。
方法1:EOF标准输出作为expect标准输入
#!/bin/bash
USER=root # 设置要登录的远程主机的用户名
PASS=123.com # 设置远程主机用户的登录密码
IP=192.168.1.120 # 设置远程主机的 IP 地址
expect << EOF # 使用 expect 来编写自动化交互脚本
set timeout 30 # 设置超时时间为 30 秒
spawn ssh $USER@$IP # 使用 spawn 命令启动 ssh 进行远程登录连接
expect {
"(yes/no)" {send "yes\r"; exp_continue} # 如果出现 "(yes/no)" 提示,自动发送 "yes" 并继续等待
"password:" {send "$PASS\r"} # 如果出现 "password:" 提示,自动发送密码进行登录
}
expect "$USER@*" {send "$1\r"} # 在成功登录后,根据需要执行的操作,这里发送了一个 $1 变量
expect "$USER@*" {send "exit\r"} # 执行完操作后,发送 "exit" 命令退出登录
expect eof # 等待所有交互完成后,终止 expect 脚本
EOF
这段代码使用了 expect 工具编写了一个自动化交互脚本,用于实现通过 SSH 远程登录到指定主机,并执行一些操作。
在 expect 命令的使用过程中:
这段代码的目的是使用 expect 实现自动化登录远程主机,并在登录后执行指定的操作。
方法2:
#!/bin/bash
USER=root # 设置要登录的远程主机的用户名
PASS=123.com # 设置远程主机的登录密码
IP=192.168.1.120 # 设置远程主机的 IP 地址
expect -c " # 使用 expect 命令编写内联脚本
spawn ssh $USER@$IP # 使用 spawn 命令启动 ssh 进程进行远程登录连接
expect {
\"(yes/no)\" {send \"yes\r\"; exp_continue} # 如果出现 "(yes/no)" 提示,自动发送 "yes" 并继续等待
\"password:\" {send \"$PASS\r\"; exp_continue} # 如果出现 "password:" 提示,自动发送密码并继续等待
\"$USER@*\" {send \"df -h\r exit\r\"; exp_continue} # 如果成功登录,发送 "df -h" 命令查看磁盘使用情况,并发送 "exit" 命令退出登录
}"
这段代码使用了 expect 工具以内联脚本的方式编写,实现了通过 SSH 登录到指定主机,并执行特定命令的自动化操作。
在 expect -c 命令中:
这段代码的目的是通过 expect 实现自动化登录远程主机,并在登录后执行特定命令,如查看磁盘使用情况,并最后退出登录。
Linux主机SSH连接信息:旧密码
# cat old_pass.txt
192.168.18.217 root 123456 22
192.168.18.218 root 123456 22
内容格式:IP User Password Port
SSH远程修改密码脚本:新密码随机生成
#!/bin/bash
OLD_INFO=old_pass.txt # 存储旧密码信息的文件路径
NEW_INFO=new_pass.txt # 存储新密码信息的文件路径
for IP in $(awk '/^[^#]/{print $1}' $OLD_INFO); do # 使用 awk 命令遍历获取每行的 IP 地址
USER=$(awk -v I=$IP 'I==$1{print $2}' $OLD_INFO) # 根据 IP 地址获取对应的用户名
PASS=$(awk -v I=$IP 'I==$1{print $3}' $OLD_INFO) # 根据 IP 地址获取对应的密码
PORT=$(awk -v I=$IP 'I==$1{print $4}' $OLD_INFO) # 根据 IP 地址获取对应的端口号
NEW_PASS=$(mkpasswd -l 8) # 使用 mkpasswd 命令生成一个具有 8 个字符长度的随机密码
echo "$IP $USER $NEW_PASS $PORT" >> $NEW_INFO # 将新的密码信息追加到新密码文件中
expect -c "
spawn ssh -p$PORT $USER@$IP # 使用 spawn 命令启动 ssh 进程进行远程登录连接
set timeout 2 # 设置超时时间为 2 秒
expect {
\"(yes/no)\" {send \"yes\r\"; exp_continue} # 如果出现 "(yes/no)" 提示,自动发送 "yes" 并继续等待
\"password:\" {send \"$PASS\r\"; exp_continue} # 如果出现 "password:" 提示,自动发送旧密码并继续等待
\"$USER@*\" {send \"echo \'$NEW_PASS\' | passwd --stdin $USER\r exit\r\"; exp_continue} # 如果成功登录,发送命令将新密码设置为随机生成的新密码,并发送 "exit" 命令退出登录
}"
done
生成新密码文件:
# cat new_pass.txt
192.168.18.217 root n8wX3mU% 22
192.168.18.218 root c87;ZnnL 22
for ((i=1;i<=9;i++)); do # 外层循环,控制行数,从 1 到 9
for ((j=1;j<=i;j++)); do # 内层循环,控制每行的乘法表达式,从 1 到当前行数
result=$(($i*$j)) # 计算乘法结果
echo -n "$j*$i=$result " # 打印乘法表达式和结果,不换行
done
echo # 内层循环结束后换行
done
这段代码的作用是打印一个简单的乘法表,从 1 到 9,按行输出。
在外层循环中,i 控制当前行数,从 1 到 9 逐渐增加。
在内层循环中,j 控制每行的乘法表达式,从 1 到当前行数 逐渐增加。
在每次内层循环中,计算乘法结果 result 的值,并使用 echo -n 打印乘法表达式和结果,不换行。
内层循环结束后,使用 echo 单独打印一个换行符,换行后进入下一行的循环。
这段代码的输出结果是一个九九乘法表。
#!/bin/bash
echo "请输入斐波那契数列的长度:"
read length # 获取用户输入的斐波那契数列长度
# 初始化前两个斐波那契数
num1=0 # 第一个斐波那契数为 0
num2=1 # 第二个斐波那契数为 1
# 输出前两个数
echo "斐波那契数列的前 $length 个数为:"
echo -n "$num1 $num2" # 输出第一个和第二个斐波那契数
# 循环计算并输出斐波那契数列
for ((i=2;i<$length;i++))
do
sum=$(($num1 + $num2)) # 计算下一个斐波那契数
echo -n " $sum" # 输出计算得到的斐波那契数
num1=$num2 # 更新第一个斐波那契数为当前的第二个斐波那契数
num2=$sum # 更新第一个斐波那契数为当前的计算结果
done
echo "" # 输出换行符,使结果美观
这段代码的作用是根据用户输入的长度,生成并输出相应长度的斐波那契数列。
通过循环计算斐波那契数列,并输出结果: