宁波网站建设哪家比较好,即将倒闭的设计院,重庆企业网站设计制作,网站开发介绍先了解下编写Shell过程中注意事项
开头加解释器#xff1a;#!/bin/bash语法缩进#xff0c;使用四个空格#xff1b;多加注释说明。命名建议规则#xff1a;全局变量名大写、局部变量小写#xff0c;函数名小写#xff0c;名字体现出实际作用。默认变量是全局的#xf…先了解下编写Shell过程中注意事项
开头加解释器#!/bin/bash语法缩进使用四个空格多加注释说明。命名建议规则全局变量名大写、局部变量小写函数名小写名字体现出实际作用。默认变量是全局的在函数中变量local指定为局部变量避免污染其他作用域。有两个命令能帮助我调试脚本set -e 遇到执行非0时退出脚本set-x 打印执行过程。写脚本一定先测试再到生产上。
1、获取随机字符串或数字
获取随机8位字符串
方法1
# echo $RANDOM |md5sum |cut -c 1-8
c9f36977
#这个命令使用$RANDOM变量生成一个随机的整数然后将其经过MD5哈希处理并使用cut命令截取前8个字符作为生成的随机字符串。
方法2
# openssl rand -base64 4
f4Cpw
#这个命令使用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位数字2、定义一个颜色输出字符串函数
方法1# 定义一个输出带颜色文本的函数
function echo_color() {# 判断参数值是否为 greenif [ $1 green ]; then# 使用绿色的前景色输出文本echo -e \e[1;32m$2\e[0m# 判断参数值是否为 redelif [ $1 red ]; then# 使用红色的前景色输出文本echo -e \033[31m$2\033[0mfi
}
方法2# 定义一个输出带颜色文本的函数
function echo_color() {# 根据参数值进行匹配case $1 in# 如果参数值为 greengreen)# 使用绿色的前景色输出文本echo -e \e[1;32m$2\e[0m;;# 如果参数值为 redred)# 使用红色的前景色输出文本echo -e \033[31m$2\033[0m;;*) # 参数值不在以上两种情况则输出提示信息echo Example: echo_color red stringesac
}
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”。3、批量创建用户
#!/bin/bash
DATE$(date %F_%T) # 当前日期和时间用于备份文件的命名
USER_FILEuser.txt # 用户文件名# 定义一个输出带颜色文本的函数
echo_color(){if [ $1 green ]; thenecho -e \e[1;32m$2\e[0m # 输出绿色文本elif [ $1 red ]; thenecho -e \033[31m$2\033[0m # 输出红色文本fi
}# 如果用户文件存在并且大小大于0就备份
if [ -s $USER_FILE ]; thenmv $USER_FILE ${USER_FILE}-${DATE}.bak # 备份用户文件echo_color green $USER_FILE exist, rename ${USER_FILE}-${DATE}.bak # 输出提示信息绿色文本
fiecho -e User\tPassword $USER_FILE # 在用户文件中添加表头
echo ---------------- $USER_FILE # 在用户文件中添加分隔线# 创建用户并记录到用户文件中
for USER in user{1..10}; doif ! id $USER /dev/null; thenPASS$(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. # 输出创建用户成功的提示信息elseecho_color red $USER User already exists! # 输出用户已存在的提示信息红色文本fi
done主要流程
获取当前日期和时间作为备份文件的命名。定义了一个echo_color函数用于输出带颜色的文本。如果用户文件存在且文件大小大于0则将用户文件进行备份并输出相应提示信息绿色文本。向用户文件中添加表头和分隔线。使用循环创建10个用户并记录到用户文件中。如果用户不存在则生成随机密码并创建用户并将用户名和密码记录到用户文件中同时输出创建用户成功的提示信息。如果用户已经存在则输出用户已存在的提示信息红色文本。
4、检查软件包是否安装
#!/bin/bash# 检查 sysstat 软件包是否已安装
if rpm -q sysstat /dev/null; thenecho sysstat is already installed. # 输出已安装的提示信息
elseecho sysstat is not installed! # 输出未安装的提示信息
firpm -q sysstat命令用于查询系统中sysstat软件包的安装情况/dev/null用于将标准输出和标准错误输出重定向到空设备即不显示输出信息如果sysstat软件包已安装则输出sysstat is already installed.表示已经存在且已安装如果sysstat软件包未安装则输出sysstat is not installed!表示尚未安装
5、检查服务状态
#!/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 主题 dstexample.com
fiss -anu命令用于查看系统中所有的UDP连接rep -c 123用于统计结果中包含123字符串的行数ps -ef命令用于查看系统中的所有进程grep ntpd用于过滤出包含ntpd字符串的行grep -vc grep用于过滤掉包含grep字符串的行并统计过滤后的行数
6、检查主机存活状态
方法1将错误IP放到数组里面判断是否ping失败三次
#!/bin/bashIP_LIST192.168.18.1 192.168.1.1 192.168.18.2# 循环处理 IP_LIST 中的每个 IP 地址
for IP in $IP_LIST; doNUM1 # 用于记录当前重试次数的变量# 使用 while 循环最多重试 3 次while [ $NUM -le 3 ]; do# 检测指定 IP 地址是否可以通过 ping 命令连通if ping -c 1 $IP /dev/null; thenecho $IP Ping is successful. # 输出提示信息表示 Ping 成功break # 跳出当前循环继续处理下一个 IP 地址else# 如果 ping 失败记录失败次数和相应的 IP 地址FAIL_COUNT[$NUM]$IPlet NUMfidone# 如果连续失败次数达到 3 次则输出错误信息并清空 FAIL_COUNT 数组if [ ${#FAIL_COUNT[*]} -eq 3 ];thenecho ${FAIL_COUNT[1]} Ping is failure! # 输出提示信息表示 Ping 失败unset FAIL_COUNT[*] # 清空 FAIL_COUNT 数组的内容fi
doneIP_LIST 字符串包含要检测的多个 IP 地址。使用 for 循环遍历每个 IP 地址。NUM 变量记录每个 IP 地址的重试次数。 代码的功能对于 IP_LIST 中的每个 IP 地址 使用 while 循环尝试最多 3 次进行 ping 命令检测。如果 ping 成功则输出提示信息表示 Ping 成功并跳出循环继续处理下一个 IP 地址。如果 ping 失败则记录失败次数和相应的 IP 地址。如果连续失败次数达到 3 次则输出错误信息并清空 FAIL_COUNT 数组。
方法2将错误次数放到FAIL_COUNT变量里面判断是否ping失败三次
#!/bin/bashIP_LIST192.168.18.1 192.168.1.1 192.168.18.2# 循环处理 IP_LIST 中的每个 IP 地址
for IP in $IP_LIST; doFAIL_COUNT0 # 用于记录失败次数的变量# 使用 for 循环尝试最多 3 次 ping 命令for ((i1;i3;i)); do# 检测指定 IP 地址是否可以通过 ping 命令连通if ping -c 1 $IP /dev/null; thenecho $IP Ping is successful. # 输出提示信息表示 Ping 成功break # 跳出当前循环继续处理下一个 IP 地址elselet FAIL_COUNT # 失败次数加 1fidone# 如果连续失败次数达到 3 次则输出错误信息if [ $FAIL_COUNT -eq 3 ]; thenecho $IP Ping is failure! # 输出提示信息表示 Ping 失败fi
doneIP_LIST 字符串包含要检测的多个 IP 地址。使用 for 循环遍历每个 IP 地址。FAIL_COUNT 变量用于记录每个 IP 地址的失败次数。 代码的功能对于 IP_LIST 中的每个 IP 地址 使用 for 循环尝试最多 3 次 ping 命令检测。如果 ping 成功则输出提示信息表示 Ping 成功并跳出循环继续处理下一个 IP 地址。如果 ping 失败则增加失败次数。如果连续失败次数达到 3 次则输出错误信息表示 Ping 失败。
方法3利用for循环将ping通就跳出循环继续如果不跳出就会走到打印ping失败
#!/bin/bash# 定义函数用于检测 Ping 状态并输出结果
ping_success_status() {if ping -c 1 $IP /dev/null; thenecho $IP Ping is successful. # 输出提示信息表示 Ping 成功continue # 继续循环处理下一个 IP 地址fi
}IP_LIST192.168.18.1 192.168.1.1 192.168.18.2# 循环处理 IP_LIST 中的每个 IP 地址
for IP in $IP_LIST; doping_success_statusping_success_statusping_success_statusecho $IP Ping is failure! # 输出提示信息表示 Ping 失败
doneping_success_status() 函数用于检测指定IP地址的Ping状态并输出结果。 IP_LIST 字符串包含要检测的多个 IP 地址。 使用 for 循环遍历每个 IP 地址对每个 IP 地址调用 ping_success_status() 函数进行 Ping 测试。 代码的功能 定义了一个名为 ping_success_status 的函数用于检测 Ping 状态并输出结果。 对于 IP_LIST 中的每个 IP 地址 分别调用 ping_success_status() 函数三次进行 Ping 测试。如果三次中有任意一次 Ping 成功则输出提示信息表示 Ping 成功并继续处理下一个 IP 地址。如果三次都 Ping 失败则输出提示信息表示 Ping 失败。
7、监控CPU、内存利用率
1CPU 借助vmstat工具来分析CPU统计信息。
#!/bin/bashDATE$(date %F %H:%M) # 获取当前日期和时间
IP$(ifconfig eth0 | awk -F[ :] /inet addr/{print $4}) # 获取 eth0 网卡的 IP 地址在 CentOS 6 中
MAILexamplemail.com# 检查系统是否安装了 vmstat 命令如果没有找到则输出错误信息并退出脚本
if ! which vmstat /dev/null; thenecho vmstat command not found. Please install the procps package.exit 1
fi# 使用 vmstat 命令获取 CPU 相关的统计数据
US$(vmstat 1 3 | awk NR5{print $13}) # 用户CPU时间占用百分比
SY$(vmstat 1 3 | awk NR5{print $14}) # 系统CPU时间占用百分比
IDLE$(vmstat 1 3 | awk NR5{print $15}) # 空闲CPU时间百分比
WAIT$(vmstat 1 3 | awk NR5{print $16}) # IO等待百分比USE$(($US$SY)) # 计算用户CPU时间占用和系统CPU时间占用的总和# 检查 CPU 使用率是否超过阈值80%如果超过则发送电子邮件通知
if [ $USE -ge 80 ]; thenecho Date: $DATEHost: $IPProblem: CPU utilization $USE | mail -s CPU Monitor $MAIL
fi代码的功能
声明并初始化了 DATE 变量用于存储当前的日期和时间。使用 ifconfig 命令获取 eth0 网卡的 IP 地址在 CentOS 6 中。设置邮件接收地址 MAIL。检查系统是否安装了 vmstat 命令如果没有找到则输出错误信息并退出脚本。、使用 vmstat 命令获取 CPU 相关的统计数据包括用户 CPU 时间占用、系统 CPU 时间占用、空闲 CPU 时间和 IO 等待时间。计算用户 CPU 时间占用和系统 CPU 时间占用的总和并存储在 USE 变量中。检查 CPU 使用率是否超过阈值80%如果超过则发送电子邮件通知包括日期、主机名和问题描述。
2内存
#!/bin/bashDATE$(date %F %H:%M) # 获取当前日期和时间
IP$(ifconfig eth0 | awk -F[ :] /inet addr/{print $4}) # 获取 eth0 网卡的 IP 地址在 CentOS 6 中
MAILexamplemail.com# 使用 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 ]; thenecho Date: $DATEHost: $IPProblem: Total$TOTAL, Use$USE, Free$FREE | mail -s Memory Monitor $MAIL
fi代码的功能
声明并初始化了 DATE 变量用于存储当前的日期和时间。使用 ifconfig 命令获取 eth0 网卡的 IP 地址在 CentOS 6 中。设置邮件接收地址 MAIL。使用 free 命令获取内存相关的统计数据包括内存总量、已使用的内存量和剩余的内存量。计算剩余内存量Total - Use并存储在 FREE 变量中。检查剩余内存量是否小于 1G1024MB如果小于则发送电子邮件通知包括日期、主机名和问题描述。
8、批量主机磁盘利用率监控
前提监控端和被监控端SSH免交互登录或者密钥登录。
写一个配置文件保存被监控主机SSH连接信息文件内容格式IP User Port
#!/bin/bashHOST_INFOhost.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; doPART_NAME${USE_RATE%*} # 获取挂载点部分即等号左边的值USE_RATE${USE_RATE#*} # 获取磁盘利用率部分即等号右边的值# 判断磁盘利用率是否超过阈值80%如果超过则将警告信息添加到邮件内容文件中if [ $USE_RATE -ge 80 ]; thenecho Warning: $PART_NAME Partition usage $USE_RATE%! mail.txtelseecho 服务器$IP的$PART_NAME目录空间良好fidone# 发送邮件将邮件内容文件作为内容邮件主题为 空间不足警告cat mail.txt | mail -s 空间不足警告 xiaobaicdeledu.com
done代码的功能
定义 HOST_INFO 变量表示保存主机信息的文件路径。删除已存在的邮件内容文件 mail.txt。使用 awk 从主机信息文件中提取非注释行的 IP 地址并依次处理每个 IP。从主机信息文件中获取用户名和端口信息。定义临时文件路径 TMP_FILE用于保存远程主机的磁盘信息。使用 ssh 命令通过公钥登录到远程主机在远程主机上执行 df -h 命令并将输出重定向到临时文件中。从临时文件中提取磁盘利用率信息并保存到 USE_RATE_LIST 变量中。使用循环遍历磁盘利用率列表并进行判断。获取挂载点部分和磁盘利用率部分。如果磁盘利用率超过阈值80%将警告信息添加到邮件内容文件 mail.txt 中。如果磁盘利用率未超过阈值则输出相应信息表示磁盘空间良好。使用 cat 命令将邮件内容文件作为邮件内容向 xiaobaicdeledu.com 发送邮件邮件主题为 “空间不足警告”。
9、检查网站可用性
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 ]; thenecho Warning: $1 Access failure!# 如果 HTTP 状态码不等于 200即不成功则输出警告信息表示 URL 访问失败fi
}# 方法2使用 wget 命令检查 URL 的访问状态
check_url() {if ! wget -T 10 --tries1 --spider $1 /dev/null 21; then # 使用 wget 命令以爬虫模式检查 URL 的访问状态超时时间为 10 秒并尝试访问 1 次将输出重定向到 /dev/null将错误输出重定向到标准输出并丢弃echo Warning: $1 Access failure!# 如果 wget 命令返回非零退出码则输出警告信息表示 URL 访问失败fi
}代码的功能
方法1使用 curl 命令。通过设置选项 -o /dev/null–connect-timeout 3-s 和 -w “%{http_code}”来测试 HTTP 头并将 HTTP 状态码保存到变量 HTTP_CODE 中。然后检查 HTTP 状态码是否等于 200如果不等于则输出警告信息表示 URL 访问失败。方法2使用 wget 命令。通过设置选项 -T 10–tries1 和 --spider以爬虫模式测试URL的访问状态并设置超时时间为10秒尝试访问1次。使用重定向将输出和错误信息都丢弃。然后检查 wget 命令的返回值如果返回非零退出码则输出警告信息表示 URL 访问失败。
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 ]; thencontinue# 如果 HTTP 状态码等于 200即成功则继续循环不执行后续操作fi
}URL_LISTwww.baidu.com www.agasgf.com
# 存储待检查的 URL 列表for URL in $URL_LIST; docheck_url $URL# 依次遍历 URL 列表调用 check_url 函数检查每个 URL 的访问状态# 如果返回的 HTTP 状态码等于 200则继续循环不执行后续操作check_url $URLcheck_url $URL# 连续调用 check_url 函数最多尝试三次echo Warning: $URL Access failure!# 输出警告信息表示 URL 访问失败
done代码的功能
定义了函数 check_url()用于检查 URL 的访问状态。通过设置选项 -o /dev/null–connect-timeout 3-s 和 -w “%{http_code}”使用 curl 命令测试 HTTP 头并将返回的 HTTP 状态码保存到变量 HTTP_CODE 中。在函数中如果返回的 HTTP 状态码等于 200那么继续循环不执行后续操作。定义了一个字符串变量 URL_LIST用于存储待检查的 URL 列表。使用 for 循环遍历 URL_LIST 中的每个 URL依次调用 check_url 函数来检查 URL 的访问状态。在每次循环中连续调用 check_url 函数最多尝试三次。如果访问失败即返回的 HTTP 状态码不等于 200则输出警告信息表示 URL 访问失败。
方法2错误次数保存到变量
#!/bin/bashURL_LISTwww.baidu.com www.agasgf.com
# 存储待检查的 URL 列表for URL in $URL_LIST; doFAIL_COUNT0# 用于统计 URL 访问失败的次数的变量for ((i1;i3;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 ]; thenlet FAIL_COUNT# 如果 HTTP 状态码不等于 200即访问失败则将失败次数加一elsebreak# 如果 HTTP 状态码等于 200即访问成功则跳出循环不执行后续尝试fidoneif [ $FAIL_COUNT -eq 3 ]; thenecho Warning: $URL Access failure!# 如果 URL 访问失败的次数等于 3即尝试了三次都失败则输出警告信息表示 URL 访问失败fi
done代码的功能
定义了一个字符串变量 URL_LIST用于存储待检查的 URL 列表。使用 for 循环遍历 URL_LIST 中的每个 URL。在每次循环中初始化变量 FAIL_COUNT 为 0用于统计 URL 访问失败的次数。使用 for 循环进行最多三次的访问尝试。在每次尝试中使用 curl 命令测试 URL 的 HTTP 头超时时间为 3 秒并将返回的 HTTP 状态码保存到变量 HTTP_CODE 中如果 HTTP 状态码不等于 200即访问失败则将 FAIL_COUNT 的值加一。如果 HTTP 状态码等于 200即访问成功则跳出循环不执行后续尝试。在完成三次访问尝试后如果失败次数等于 3则输出警告信息表示 URL 访问失败。
方法3错误次数保存到数组
#!/bin/bashURL_LISTwww.baidu.com www.agasgf.com
# 存储待检查的 URL 列表for URL in $URL_LIST; doNUM1# 用于计数的变量 NUM初始值为 1while [ $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 ]; thenFAIL_COUNT[$NUM]$IP# 如果 HTTP 状态码不等于 200即访问失败则将失败的 URL 存储到数组 FAIL_COUNT 中以 NUM 作为下标IP 作为元素let NUM# 数量加一进行下一次尝试elsebreak# 如果 HTTP 状态码等于 200即访问成功则跳出循环不再进行尝试fidoneif [ ${#FAIL_COUNT[*]} -eq 3 ]; thenecho Warning: $URL Access failure!unset FAIL_COUNT[*]# 如果 FAIL_COUNT 数组中有三个元素即进行了三次尝试都失败则输出警告信息表示 URL 访问失败并清空 FAIL_COUNT 数组fi
done代码的功能
定义了一个字符串变量 URL_LIST用于存储待检查的 URL 列表。使用 for 循环遍历 URL_LIST 中的每个 URL。在每次循环中初始化变量 NUM 为 1用于计数访问尝试的次数。使用 while 循环进行最多三次的访问尝试。在每次尝试中使用 curl 命令测试 URL 的 HTTP 头超时时间为 3 秒并将返回的 HTTP 状态码保存到变量 HTTP_CODE 中。如果 HTTP 状态码不等于 200即访问失败则将失败的 URL 存储到 FAIL_COUNT 数组中以 NUM 作为下标IP 作为元素。然后NUM 加一进行下一次尝试。如果 HTTP 状态码等于 200即访问成功则跳出循环不再进行尝试。 使用 for 循环遍历 URL_LIST 中的每个 URL。在完成三次访问尝试后如果 FAIL_COUNT 数组中有三个元素即进行了三次尝试都失败则输出警告信息表示 URL 访问失败并清空 FAIL_COUNT 数组。
10、检查MySQL主从同步状态
#!/bin/bashUSERbak
PASSWD123456IO_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; doTHREAD_STATUS_NAME${i%:*}# 通过 %:* 取 THREAD_STATUS_NAME 字符串变量获取冒号前的部分THREAD_STATUS${i#*:}# 通过 #*: 取 THREAD_STATUS 字符串变量获取冒号后的部分if [ $THREAD_STATUS ! Yes ]; thenecho Error: MySQL Master-Slave $THREAD_STATUS_NAME status is $THREAD_STATUS!# 如果 THREAD_STATUS 不等于 Yes则输出错误信息表示 MySQL 主从状态异常fi
done代码的功能
定义了字符串变量 USER 和 PASSWD分别存储登录 MySQL 的用户名和密码。使用 mysql 命令执行查询语句 show slave statusG获取 MySQL 主从复制的状态。-u$ USER 指定用户名-p$PASSWD 指定密码-e 后面跟查询语句G 匹配 show slave status 的输出格式。使用 awk 命令根据关键字 “Slave_.*_Running” 解析出对应的行并去除冒号后的空格。使用 for 循环遍历 $IO_SQL_STATUS 中的每个值。在每次循环中通过 %* 取出冒号前的部分赋值给 THREAD_STATUS_NAME 变量。通过 #*: 取出冒号后的部分赋值给 THREAD_STATUS 变量。如果 THREAD_STATUS 不等于 “Yes”则输出错误信息表示 MySQL 主从状态异常。
11、iptables自动屏蔽访问网站频繁的IP
场景恶意访问,安全防范 1屏蔽每分钟访问超过200的IP 方法1根据访问日志Nginx为例
#!/bin/bashDATE$(date %d/%b/%Y:%H:%M)
# 获取当前日期和时间并格式化为 %d/%b/%Y:%H:%M 的形式赋值给变量 DATEABNORMAL_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_IPfor 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 地址加入防火墙规则拒绝其输入流量。 代码的功能
定义了字符串变量 DATE使用 date 命令获取当前日期和时间并使用 %d/%b/%Y:%H:%M 格式化。使用 tail 命令读取文件 access.log 的最后 5000 行日志。使用 grep 过滤出包含当前日期的行。使用 awk 命令统计 IP 地址出现的次数将出现次数大于 100 的 IP 地址打印出来赋值给变量 ABNORMAL_IP。使用 for 循环遍历 ABNORMAL_IP 中的每个 IP 地址。使用 iptables 命令查看当前防火墙规则使用 grep 过滤出包含指定 IP 地址的行并使用 -c 参数统计匹配行的数量。如果匹配行的数量等于 0表示当前 IP 地址不在防火墙规则中。使用 iptables 命令在 INPUT 链的开头插入一条规则拒绝指定 IP 地址的所有输入流量。
方法2通过TCP建立的连接
#!/bin/bashABNORMAL_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_IPfor 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 地址加入防火墙规则。 代码的功能
使用 netstat 命令获取当前的网络连接状态。使用 awk 过滤出本地端口为 80 的已建立连接ESTABLISHED的行并使用 gsub 函数将客户端 IP 地址中的冒号和端口号去除。统计每个 IP 地址的出现次数如果次数大于 100则将 IP 地址打印出来赋值给变量 ABNORMAL_IP。使用 for 循环遍历 ABNORMAL_IP 中的每个 IP 地址。使用 iptables 命令查看当前防火墙规则使用 grep 过滤出包含指定 IP 地址的行并使用 -c 参数统计匹配行的数量。如果匹配行的数量等于 0表示当前 IP 地址不在防火墙规则中。使用 iptables 命令在 INPUT 链的开头插入一条规则拒绝指定 IP 地址的所有输入流量。
2屏蔽每分钟SSH尝试登录超过10次的IP 方法1通过lastb获取登录状态
#!/bin/bashDATE$(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_IPfor 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 地址加入防火墙规则禁止其输入流量。 代码的功能
使用 date 命令获取当前日期和时间并使用格式化字符串 “%a %b %e %H:%M” 格式化成星期几、月份、日期、小时和分钟的形式赋值给变量 DATE。使用 lastb 命令获取登录失败的记录。使用 grep 过滤出包含当前日期的行。使用 awk 命令统计每个 IP 地址出现的次数如果次数大于 10则将 IP 地址打印出来赋值给变量 ABNORMAL_IP。使用 for 循环遍历 ABNORMAL_IP 中的每个 IP 地址。使用 iptables 命令查看当前防火墙规则使用 grep 过滤出包含指定 IP 地址的行并使用 -c 参数统计匹配行的数量。如果匹配行的数量等于 0表示当前 IP 地址不在防火墙规则中。使用 iptables 命令在 INPUT 链的开头插入一条规则拒绝指定 IP 地址的所有输入流量。
方法2通过日志获取登录状态
#!/bin/bashDATE$(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_IPfor 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 日志文件中。 代码的功能
使用 date 命令获取当前日期和时间并使用格式化字符串 “%b %d %H” 格式化成月份、日期、小时的形式赋值给变量 DATE。使用 tail 命令读取文件 /var/log/auth.log 的最后10000行日志。使用 grep 过滤出包含当前日期的行。使用 awk 命令找出包含 “Failed” 关键词的行并以行中倒数第 3 个字段即 IP 地址为 key统计出现次数。如果次数大于 5则将 IP 地址打印出来赋值给变量 ABNORMAL_IP。使用 for 循环遍历 ABNORMAL_IP 中的每个 IP 地址。使用 iptables 命令查看当前防火墙规则使用 grep 过滤出包含指定 IP 地址的行并使用 -c 参数统计匹配行的数量。如果匹配行的数量等于 0表示当前 IP 地址不在防火墙规则中。使用 iptables 命令在 INPUT 链的末尾追加一条规则拒绝指定 IP 地址的所有输入流量。使用 echo 命令将执行的 iptables 命令和时间记录到 ~/ssh-login-limit.log 日志文件中。
12、判断用户输入的是否为IP地址
方法1:
#!/bin/bash# 定义函数 check_ip用于检查输入的 IP 地址是否合法
function check_ip(){local IP$1VALID_CHECK$(echo $IP | awk -F. {if($1255$2255$3255$4255) print yes; else print no})# 将 IP 地址按照 . 分隔成四个字段并使用 awk 判断每个字段的取值范围是否合法0-255if 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 ]]; thenecho $IP available.return 0elseecho $IP not available!return 1fielseecho Format error!return 1fi
}while true; doread -p Please enter IP: ip# 提示用户输入 IP 地址并将输入保存到变量 ip 中check_ip $ip# 调用函数 check_ip传入用户输入的 IP 地址作为参数进行检查# 如果函数返回值为 0表示 IP 地址合法跳出循环# 如果函数返回值为 1表示 IP 地址不合法继续循环
done这段代码实现了一个循环提示用户输入 IP 地址并通过调用函数 check_ip 对输入的 IP 地址进行检查直到用户输入合法的 IP 地址为止。 代码的功能
定义了一个函数 check_ip用于检查输入的 IP 地址是否合法。在函数内部首先将 IP 地址按照 “.” 分隔成四个字段并使用 awk 判断每个字段的取值范围是否合法0-255。使用正则表达式验证 IP 地址的格式必须为 1-3 位数字 “.” 1-3 位数字 “.” 1-3 位数字 “.” 1-3 位数字。如果 IP 地址格式合法并且每个字段的取值也合法输出 “IP available.”。如果 IP 地址格式合法但有字段取值不合法输出 “IP not available!”。如果 IP 地址格式不合法输出 “Format error!”。在 while 循环中使用 read 命令提示用户输入 IP 地址并将输入保存到变量 ip 中。调用 check_ip 函数传入用户输入的 IP 地址作为参数进行检查。如果函数返回值为 0表示 IP 地址合法跳出循环。如果函数返回值为 1表示 IP 地址不合法继续循环。
方法2
#!/bin/bash# 定义函数 check_ip用于检查输入的 IP 地址是否合法
function check_ip(){IP$1if [[ $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# 判断每个字段的取值是否都小于等于 255echo $IP available.# 输出 IP 地址合法elseecho $IP not available!# 输出 IP 地址不合法至少有一个字段的取值大于 255fielseecho 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用于检查输入的 IP 地址是否合法。使用正则表达式验证 IP 地址的格式必须为 1-3 位数字 “.” 1-3 位数字 “.” 1-3 位数字 “.” 1-3 位数字。使用 cut 命令按照 “.” 分割 IP 地址并分别将每个字段赋值给对应的变量。判断每个字段的取值是否都小于等于 255。如果 IP 地址合法且每个字段的取值都小于等于 255输出 “IP available.”。如果 IP 地址合法但至少有一个字段的取值大于 255输出 “IP not available!”。如果 IP 地址不合法输出 “Format error!”。
在主程序中调用 check_ip 函数进行两次检查
第一次传入参数 192.168.1.1 进行检查输出 “192.168.1.1 available.”表示该 IP 地址合法。第二次传入参数 256.1.1.1 进行检查输出 “256.1.1.1 not available!”表示该 IP 地址不合法有一个字段的取值大于 255。
13、判断用户输入的是否为数字
方法1
#!/bin/bash# 使用正则表达式判断参数是否为数字
if [[ $1 ~ ^[0-9]$ ]]; thenecho Is Number.# 如果参数是由一个或多个数字组成输出 Is Number.
elseecho No Number.# 如果参数不是由一个或多个数字组成输出 No Number.
fi段代码使用正则表达式判断参数是否为数字。 代码的功能
使用正则表达式 ^ [0-9]$ 判断参数是否由一个或多个数字组成。 ^ 表示匹配字符串的起始位置。[0-9] 表示匹配数字字符的范围即 0 到 9。表示匹配前面的元素一次或多次。$表示匹配字符串的结束位置。 如果参数是由一个或多个数字组成即满足正则表达式的匹配条件输出 “Is Number.”。如果参数不是由一个或多个数字组成即不满足正则表达式的匹配条件输出 “No Number.”。
方法2
#!/bin/bash# 判断参数是否为一个数字
if [ $1 -gt 0 ] 2/dev/null; thenecho Is Number.# 如果参数大于 0即参数是一个数字输出 Is Number.
elseecho No Number.# 如果参数不是一个数字输出 No Number.
fi这段代码使用条件判断语句判断参数是否为一个数字。 代码的功能
使用条件判断语句 [ … ] 判断 $1 是否大于 0。 $1 表示脚本或函数的第一个参数用于接收命令行传入的参数。-gt 是一个数值比较操作符表示大于。 2/dev/null 表示将标准错误输出重定向到 /dev/null即丢弃错误输出。 这是为了避免在参数不是一个数字时生成不必要的错误输出。 如果参数大于 0即满足条件判断输出 “Is Number.”。如果参数不是一个数字即不满足条件判断输出 “No Number.”。
方法3
#!/bin/bashecho $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 命令和三元运算符来判断参数是否是一个数字并进行相应的输出。
14、给定目录找出包含关键字的文件
#!/bin/bashDIR$1 # 存储目录路径
KEY$2 # 存储要搜索的关键词# 使用循环逐个遍历目录下的文件
for FILE in $(find $DIR -type f); do# 在文件中搜索关键词并将输出重定向到 /dev/null即丢弃匹配结果if grep $KEY $FILE /dev/null; thenecho -- $FILE# 如果搜索到关键词输出文件路径fi
done这段代码的功能是在给定的目录中搜索包含指定关键词的文件并输出文件的路径。 代码的功能
DIR$1将第一个命令行参数赋值给变量 DIR用于存储目录路径。KEY$2将第二个命令行参数赋值给变量 KEY用于存储要搜索的关键词。for FILE in $(find $DIR -type f); do … done使用循环逐个遍历目录下的文件。find $DIR -type f使用 find 命令在目录 $DIR 中搜索所有类型为文件的项并将结果以空格分隔输出。grep $KEY $FILE /dev/null在文件 $FILE 中搜索关键词 $KEY并将匹配结果重定向到 /dev/null即丢弃匹配结果。 grep 命令用于在文本中搜索指定的模式这里用于搜索关键词。 是重定向的语法将标准输出和标准错误输出都重定向到同一个地方这里是 /dev/null即丢弃匹配结果。 if grep $KEY $FILE /dev/null; then … fi如果搜索到关键词则进入条件判断语句。echo “– $FILE”在终端输出带有 -- 前缀的文件路径即输出搜索到的文件路径。
15、监控目录将新创建的文件名追加到日志中
场景记录目录下文件操作。
需先安装inotify-tools软件包。
-m #持续监听
-r #使用递归形式监控目录
-q #减少冗余信息只打印出需要的信息
-e #指定要监控的事件多个事件使用逗号隔开access #访问读取文件modify #修改文件内容被修改attrib #属性文件元数据被修改move #移动对文件进行移动操作 move_to move_fromcreate #创建生成新文件open #打开对文件进行打开操作close #关闭对文件进行关闭操作 close_write close_nowritedelete #删除文件被删除 delete_selfunmount #卸载文件或目录的文件系统
--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 adminip:/tmp
done这段代码的功能是使用 inotifywait 监视指定目录中的文件创建事件并在有文件创建时执行 rsync 命令。 代码的功能
MON_DIR/tmp将 /tmp 目录路径赋值给变量 MON_DIR表示要监视的目录。inotifywait -mq --format %f -e create $MON_DIR使用 inotifywait 命令监视目录 $MON_DIR 中的文件创建事件并以简洁的格式输出文件名。while read files; do … done使用 while 循环逐行读取输出的文件名。echo rsync -avz $files adminip:/tmp对于每个读取的文件名输出 rsync 命令。 rsync 命令用于文件同步和传输。-avz 表示启用归档模式并压缩传输。$files 表示读取到的文件名即待同步的文件。adminip:/tmp 表示目标地址具体的 IP 地址和目录可以根据实际情况进行修改。
16、给用户提供多个网卡选择
场景服务器多个网卡时获取指定网卡例如网卡流量
#!/bin/bashfunction local_nic() {local NUM ARRAY_LENGTHNUM0for NIC_NAME in $(ls /sys/class/net | grep -vE lo|docker0); doNIC_IP$(ifconfig $NIC_NAME | awk -F[: ] /inet addr/{print $4})if [ -n $NIC_IP ]; thenNIC_IP_ARRAY[$NUM]$NIC_NAME:$NIC_IP# 将网卡名和对应IP放到数组let NUMfidoneARRAY_LENGTH${#NIC_IP_ARRAY[*]}# 获取数组长度if [ $ARRAY_LENGTH -eq 1 ]; then# 如果数组里面只有一条记录说明只有一个网卡NIC${NIC_IP_ARRAY[0]%:*}# 获取网卡名称去除IP地址部分return 0elif [ $ARRAY_LENGTH -eq 0 ]; then# 如果没有记录说明没有可用的网卡echo No available network card!exit 1else# 如果有多条记录则提醒输入选择for NIC in ${NIC_IP_ARRAY[*]}; doecho $NIC# 输出所有网卡名称和对应的IP地址donewhile true; doread -p Please enter the name of the network card to use: INPUT_NIC_NAME# 提示用户输入要使用的网卡名称COUNT0for NIC in ${NIC_IP_ARRAY[*]}; doNIC_NAME${NIC%:*}if [ $NIC_NAME $INPUT_NIC_NAME ]; thenNIC${NIC_IP_ARRAY[$COUNT]%:*}# 获取用户输入网卡名称对应的IP地址return 0elseCOUNT1fidoneecho Not match! Please input again.# 如果输入不匹配要求用户重新输入donefi
}local_nic这段代码的功能是获取本地可用的网卡和对应的IP地址并要求用户选择要使用的网卡。 代码的功能
function local_nic()定义了一个名为 local_nic 的函数。NUM0设置一个变量 NUM 为 0用于记录数组的索引。for NIC_NAME in $(ls /sys/class/net | grep -vE “lo|docker0”); do … done循环遍历 /sys/class/net 目录下的网卡名称排除 lo本地回环接口和 docker0Docker 网络接口。NIC_IP$(ifconfig $NIC_NAME | awk -F’[: ]’ ‘/inet addr/{print $4}’)获取每个网卡的 IP 地址并将结果赋值给 NIC_IP。if [ -n “$NIC_IP” ]; then … fi如果 NIC_IP 不为空即获取到了 IP 地址则执行条件判断的代码块。NIC_IP_ARRAY[$ NUM]“$ NIC_NAME:$NIC_IP”将网卡名称和对应的 IP 地址放入数组 NIC_IP_ARRAY 中索引为 $NUM。let NUM将 NUM 的值加 1用于下次循环时的数组索引。ARRAY_LENGTH${#NIC_IP_ARRAY[*]}获取数组 NIC_IP_ARRAY 的长度。if [ $ARRAY_LENGTH -eq 1 ]; then … fi如果数组长度为 1说明只有一个可用网卡。NIC${NIC_IP_ARRAY[0]%*}将数组中的第一个元素赋值给变量 NIC并去除末尾的 IP 地址部分。return 0函数执行成功返回 0。elif [ $ARRAY_LENGTH -eq 0 ]; then … fi如果数组长度为 0说明没有可用的网卡。echo “No available network card!”输出提示信息 “No available network card!”。exit 1正常退出脚本并返回状态码 1。else如果有多条可用网卡则要求用户选择要使用的网卡。for NIC in ${NIC_IP_ARRAY[*]}; do … done循环遍历数组 NIC_IP_ARRAY 中的每个元素即每个网卡名称和对应的 IP 地址。echo $NIC输出每个网卡的名称和对应的 IP 地址。while true; do … done使用无限循环要求用户输入网卡名称并进行匹配。read -p Please enter the name of the network card to use: INPUT_NIC_NAME提示用户输入要使用的网卡名称将其保存在变量 INPUT_NIC_NAME 中。COUNT0设置一个变量 COUNT 为 0用于记录数组的索引。for NIC in ${NIC_IP_ARRAY[*]}; do … done循环遍历数组 NIC_IP_ARRAY 中的每个元素即每个网卡名称和对应的 IP 地址。NIC_NAME${NIC%: *}将数组元素中的 IP 地址部分截取掉只保留网卡名称。if [ $ NIC_NAME “$INPUT_NIC_NAME” ]; then … fi如果网卡名称与用户输入的名称匹配。NIC$ {NIC_IP_ARRAY[$COUNT]%: *}将数组元素中的 IP 地址部分截取掉只保留网卡名称赋值给变量 NIC。return 0函数执行成功返回 0。else如果输入不匹配输出提示信息并要求用户重新输入。done结束内层循环。done结束函数的整体逻辑。local_nic调用 local_nic 函数。
17、查看网卡实时流量
适用于CentOS操作系统。
#!/bin/bash# Description: Only CentOS# traffic_unit_conv函数将流量转换为合适的单位KB/s或MB/s
traffic_unit_conv() {local traffic$1if [ $traffic -gt 1024000 ]; thenprintf %.1f%s $(($traffic/1024/1024)) MB/s# 如果流量大于10240001024KB将流量转换为MB/s并保留1位小数elif [ $traffic -lt 1024000 ]; thenprintf %.1f%s $(($traffic/1024)) KB/s# 如果流量小于10240001024KB将流量转换为KB/s并保留1位小数fi
}NIC$1 # 获取用户传入的参数作为要监测的网卡名称echo -e In ------ Out
# 打印标题 In ------ Outwhile 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
# 结束循环这段代码的功能是监测指定网卡的接收和发送流量并每秒打印一次流量值。 代码的功能
#Description: Only CentOS6描述脚本的作用限定适用于 CentOS 系统。traffic_unit_conv()定义了一个名为 traffic_unit_conv 的函数用于将流量转换为合适的单位KB/s或MB/s。local traffic$1将传入的第一个参数赋值给变量 traffic表示要转换的流量值。 if [ $traffic -gt 1024000 ]; then … fi如果流量值大于 10240001024KB执行条件判断的代码块。printf “%.1f%s” “$ (($traffic/1024/1024))” “MB/s”将流量值除以1024再除以1024并保留1位小数表示为 MB/s。elif [ $ traffic -lt 1024000 ]; then … fi如果流量值小于 10240001024KB执行条件判断的代码块。printf “%.1f%s” “$ (($ traffic/1024))” “KB/s”将流量值除以1024保留1位小数表示为 KB/s。NIC$ 1将传入的第一个参数赋值给变量 NIC表示要监测的网卡名称。echo -e In ------ Out打印标题 “In ------ Out”使用 -e 选项表示支持特殊字符的解释。while true; do … done进入无限循环用于持续监测流量变化。OLD_IN$ (awk -F’[: ]’ ‘$ 0~’$ NIC’{print $ 3}’ /proc/net/dev)使用 awk 命令获取当前网卡的旧的接收流量值。OLD_OUT$ (awk -F’[: ]’ ‘$ 0~’$ NIC’{print $ 11}’ /proc/net/dev)使用 awk 命令获取当前网卡的旧的发送流量值。sleep 1等待1秒以便获取新的流量数据。NEW_IN$ (awk -F’[: ]’ ‘$ 0~’$ NIC’{print $ 3}’ /proc/net/dev)使用 awk 命令获取当前网卡的新的接收流量值。NEW_OUT$ (awk -F’[: ]’ ‘$ 0~’$NIC’{print $11}’ /proc/net/dev)使用 awk 命令获取当前网卡的新的发送流量值。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
18、MySQL数据库备份
#!/bin/bashDATE$(date %F_%H-%M-%S) # 获取当前日期和时间用于备份文件名
HOST192.168.1.120 # 数据库主机地址
DBtest # 数据库名称
USERbak # 数据库用户名
PASS123456 # 数据库密码
MAILzhangsanexample.com lisiexample.com # 接收备份结果通知的邮件地址
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 ]; thenecho $DATE 内容 | mail -s 主题 $MAILfi
else# 如果备份失败发送邮件通知echo $DATE 内容 | mail -s 主题 $MAIL
fi# 删除14天前的压缩备份文件
find $BACKUP_DIR -name *.zip -ctime 14 -exec rm {} \;
这段代码的功能是备份指定数据库并将备份文件压缩最后删除过期的备份文件。 代码的功能
DATE$ (date %F_%H-%M-%S)使用 date 命令获取当前的日期和时间并赋值给变量 DATE用于生成备份文件名。HOST192.168.1.120设置数据库主机地址。DBtest设置要备份的数据库名称。USERbak设置连接数据库所使用的用户名。PASS123456设置连接数据库所使用的密码。MAIL“zhangsanexample.com lisiexample.com”设置接收备份结果通知的邮件地址多个邮件地址之间使用空格分隔。BACKUP_DIR/data/db_backup设置备份文件存储路径。SQL_FILE$ {DB}full$ DATE.sql生成 SQL 备份文件的文件名。BAK_FILE$ {DB}full$ DATE.zip生成的压缩备份文件名。cd $ BACKUP_DIR切换到备份文件存储路径。if mysqldump -h$ HOST -u$ USER -p$ PASS --single-transaction --routines --triggers -B $ DB $ SQL_FILE; then … fi使用 mysqldump 命令备份指定数据库并将结果输出到 SQL 备份文件中。如果备份成功则执行条件判断的代码块。zip $ BAK_FILE $ SQL_FILE rm -f $ SQL_FILE将 SQL 备份文件压缩为压缩备份文件并删除原始 SQL 备份文件。if [ ! -s $ BAK_FILE ]; then … fi如果压缩备份文件为空没有内容执行条件判断的代码块。echo “$DATE 内容” | mail -s “主题” $MAIL使用 mail 命令发送邮件通知邮件主题为 “主题”邮件内容包含当前的日期和时间。else … fi如果备份失败执行条件判断的代码块。find $BACKUP_DIR -name ‘*.zip’ -ctime 14 -exec rm {} ;使用 find 命令查找指定路径下14天前的所有压缩备份文件并删除它们。
19、Nginx服务管理脚本
场景使用源码包安装Nginx不含带服务管理脚本也就是不能使用service nginx start或/etc/init.d/nginx start所以写了以下的服务管理脚本。
#!/bin/bash
# Description: Only support RedHat system. /etc/init.d/functionsWORD_DIR/usr/local/nginx # Nginx安装目录
DAEMON$WORD_DIR/sbin/nginx # Nginx可执行文件路径
CONF$WORD_DIR/conf/nginx.conf # Nginx配置文件路径
NAMEnginx # 进程名称
PID$(awk -F[; ] /^[^#]/{if($0~/pid;/)print $2} $CONF) # 获取配置文件中定义的PID文件路径# 如果配置文件中未定义PID文件路径设置默认的PID文件路径
if [ -z $PID ]; thenPID$WORD_DIR/logs/nginx.pid
elsePID$WORD_DIR/$PID
fistop() {$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 instart)# 如果PID文件不存在启动Nginx进程否则输出进程正在运行的提示if [ ! -f $PID ]; thenstartelseecho $NAME is running...exit 0fi;;stop)# 如果PID文件存在停止Nginx进程否则输出进程未运行的提示if [ -f $PID ]; thenstopelseecho $NAME not running!exit 0fi;;restart)# 如果PID文件不存在输出进程未运行的提示并启动Nginx进程否则先停止再启动if [ ! -f $PID ]; thenecho $NAME not running! startelsestopstartfi;;reload)# 发送信号重新加载Nginx配置reload;;testconfig)# 检查Nginx配置文件语法是否正确test_config;;status)# 根据PID文件是否存在输出不同的状态提示[ -f $PID ] echo $NAME is running... || echo $NAME not running!;;*)# 输出脚本的使用方法并退出脚本返回退出码3echo Usage: $0 {start|stop|restart|reload|testconfig|status}exit 3;;
esac这段脚本实现了对 Nginx 服务的启停、重启、重新加载配置文件以及检查配置文件语法的功能。 代码的功能
. /etc/init.d/functions引入 /etc/init.d/functions 文件该文件包含用于输出提示信息的函数。WORD_DIR/usr/local/nginx设置 Nginx 的安装目录。DAEMON$WORD_DIR/sbin/nginx设置 Nginx 可执行文件的路径。CONF$ WORD_DIR/conf/nginx.conf设置 Nginx 的配置文件路径。NAMEnginx设置进程名称为 “nginx”。PID$ (awk -F’[; ]’ ‘/^ [ ^#]/{if($ 0~/pid;/)print $ 2}’ $ CONF)使用 awk 命令从配置文件中提取 PID 文件路径。if [ -z “$ PID” ]; then … else … fi如果 PID 文件路径为空则设置默认的 PID 文件路径为 $ WORD_DIR/logs/nginx.pid。stop() { … }定义一个函数 stop用于停止 Nginx 进程。start() { … }定义一个函数 start用于启动 Nginx 进程。reload() { … }定义一个函数 reload用于重新加载 Nginx 配置文件。test_config() { … }定义一个函数 test_config用于检查 Nginx 配置文件的语法是否正确。case “$1” in … esac根据脚本传入的参数执行不同的操作。action “* Stopping $NAME” /bin/true输出停止进程的操作提示后面的 /bin/true 表示操作成功。action “* Starting $NAME” /bin/true输出启动进程的操作提示后面的 /bin/true 表示操作成功。action “* Stopping $NAME” /bin/false输出停止进程的操作提示后面的 /bin/false 表示操作失败。action “* Starting $NAME” /bin/false输出启动进程的操作提示后面的 /bin/false 表示操作失败。if [ ! -f $PID ]; then … else … fi如果 PID 文件不存在则启动 Nginx 进程否则输出进程正在运行的提示。if [ -f $PID ]; then … else … fi如果 PID 文件存在则停止 Nginx 进程否则输出进程未运行的提示。if [ ! -f $PID ]; then … else … fi如果 PID 文件不存在则输出进程未运行的提示并启动 Nginx - 否则先停止再启动。reload发送信号重新加载 Nginx 配置。test_config检查 Nginx 配置文件的语法是否正确。[ -f $ PID ] echo “$ NAME is running…” || echo “$NAME not running!”根据 PID 文件是否存在输出不同的状态提示。echo “Usage: $0 {start|stop|restart|reload|testconfig|status}”输出脚本的使用方法。exit 3退出脚本返回退出码 3。
20、用户根据菜单选择要连接的Linux主机
Linux主机SSH连接信息
# cat host.txt
Web 192.168.1.10 root 22
DB 192.168.1.11 root 22内容格式主机名 IP User Port
#!/bin/bashPS3Please input number: # 设置 select 命令的提示信息HOST_FILEhost.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} $1NAME{print $2} $HOST_FILE)USER$(awk -v NAME${NAME} $1NAME{print $3} $HOST_FILE)PORT$(awk -v NAME${NAME} $1NAME{print $4} $HOST_FILE)if [ $IP ]; thenecho Name: $NAME, IP: $IP# 使用 ssh 命令连接远程主机使用密钥免交互登录ssh -o StrictHostKeyCheckingno -p $PORT -i id_rsa $USER$IPbreakelseecho Input error, Please enter again!breakfidone
done这段脚本实现了根据主机名从 host.txt 文件中获取主机的连接信息并使用 SSH 命令连接远程主机的功能。 代码的功能
PS3Please input number: 设置 select 命令的提示信息用于用户选择主机时显示。HOST_FILEhost.txt设置存储主机连接信息的文件路径为 host.txt。while true; do … done无限循环用于不断提供主机选择菜单。select NAME in $(awk ‘{print $1}’ $HOST_FILE) quit; do … done使用 select 命令选择主机名从 host.txt 文件中获取并加上 quit 选项用于退出脚本。[ ${NAME:empty} “quit” ] exit 0如果选择的主机名为 quit则退出脚本。IP$ (awk -v NAME${NAME} ‘$1NAME{print $2}’ $HOST_FILE)根据选择的主机名从 host.txt 文件中获取对应的 IP 地址。USER$ (awk -v NAME${NAME} ‘$1NAME{print $3}’ $HOST_FILE)根据选择的主机名从 - host.txt 文件中获取对应的用户名。PORT$ (awk -v NAME${NAME} ‘$1NAME{print $4}’ $HOST_FILE)根据选择的主机名从 host.txt 文件中获取对应的端口号。if [ $IP ]; then … else … fi如果 IP 地址存在则输出主机名和 IP 地址并使用 SSH 命令连接远程主机否则输出输入错误的提示信息。echo “Name: $NAME, IP: $IP”输出选择的主机名和对应的 IP 地址。ssh -o StrictHostKeyCheckingno -p $ PORT -i id_rsa $ USER$IP使用 SSH 命令连接远程主机其中使用 -o StrictHostKeyCheckingno 参数禁止严格的主机密钥检查-p $PORT 指定连接的端口号-i id_rsa 指定使用密钥文件进行免交互登录。break结束当前循环回到外层的无限循环等待下一次主机选择。echo “Input error, Please enter again!”输出输入错误的提示信息。exit 0退出脚本返回退出码 0。
21、从FTP服务器下载文件
#!/bin/bash# 检查参数数量是否为1
if [ $# -ne 1 ]; thenecho 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 下载指定文件的功能。 代码的功能
if [ $# -ne 1 ]; then … fi检查传入的参数数量是否为1如果不是1个参数输出用法提示信息。echo “Usage: $0 filename”输出用法提示信息告知用户正确的参数输入格式。dir$(dirname $1)获取指定文件的目录路径。file$(basename $1)获取指定文件的文件名。ftp -n -v EOF使用 ftp 命令连接 FTP 服务器并执行操作-n 参数表示在连接后不执行任何自动登录操作-v 参数表示输出详细的执行过程信息。open 192.168.1.10使用 ftp 命令连接到指定的 FTP 服务器其中 192.168.1.10 是 FTP 服务器的 IP 地址。user admin password使用指定的用户名 admin 和密码 password 进行登录。binary设置 FTP 传输模式为二进制以确保传输的文件保持原样避免出现 MD5 值不同或 .tar.gz 压缩包格式错误的问题。cd $dir切换到指定的目录。get “$ file”下载指定的文件其中 $ 用于获取变量的值“$file” 使用双引号包围变量值以处理文件名中可能包含的特殊字符。EOF表示结束 ftp 命令的输入。
22、连续输入5个100以内的数字统计和、最小和最大
#!/bin/bash# 初始化计数器、和、最小值、最大值
COUNT1
SUM0
MIN0
MAX100# 循环5次读取用户输入的整数并进行相关操作
while [ $COUNT -le 5 ]; doread -p 请输入1-10个整数 INT # 提示用户输入1-10个整数if [[ ! $INT ~ ^[0-9]$ ]]; then # 判断输入是否为整数echo 输入必须是整数exit 1 # 若输入不是整数退出脚本返回退出码 1elif [[ $INT -gt 100 ]]; then # 判断输入是否小于等于100echo 输入必须是100以内exit 1 # 若输入大于100退出脚本返回退出码 1fiSUM$(($SUM$INT)) # 累加输入的整数到和变量[ $MIN -lt $INT ] MIN$INT # 更新最小值变量[ $MAX -gt $INT ] MAX$INT # 更新最大值变量let COUNT # 计数器自增
done# 输出计算结果
echo SUM: $SUM # 输出和
echo MIN: $MIN # 输出最小值
echo MAX: $MAX # 输出最大值这段脚本实现了读取用户输入的整数计算输入的整数的和、最小值和最大值并输出结果。 代码的功能
COUNT1初始化计数器变量为1。SUM0初始化和变量为0。MIN0初始化最小值变量为0。MAX100初始化最大值变量为100。while [ $COUNT -le 5 ]; do … done循环5次用于接收和处理用户输入的整数。read -p “请输入1-10个整数” INT提示用户输入1-10个整数并将输入的值保存到变量 INT。if [[ ! $ INT ~ ^ [0-9]$ ]]; then … fi如果输入的值不是整数则提示错误并退出脚本。echo “输入必须是整数”输出提示信息告知用户输入必须是整数。exit 1退出脚本返回退出码 1。elif [[ $INT -gt 100 ]]; then … fi如果输入的值大于100则提示错误并退出脚本。echo “输入必须是100以内”输出提示信息告知用户输入必须是100以内的整数。SUM$ (($ SUM$INT))将输入的整数累加到和变量。[ $ MIN -lt $ INT ] MIN$INT更新最小值变量如果新输入的整数大于最小值则更新最小值。[ $ MAX -gt $ INT ] MAX$INT更新最大值变量如果新输入的整数小于最大值则更新最大值。let COUNT将计数器自增。echo “SUM: $SUM”输出计算的和。echo “MIN: $MIN”输出计算的最小值。echo “MAX: $MAX”输出计算的最大值。
23、将结果分别赋值给变量
应用场景希望将执行结果或者位置参数赋值给变量以便后续使用。
方法1
for i in $(echo 4 5 6); do # 循环遍历 4 5 6eval 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}拆分为到每个变量
num0 # 初始化计数器变量为0
for i in $(eval echo $*); do # 循环遍历命令行参数并使用 eval 命令展开参数中的花括号拓展表达式let num1 # 计数器自增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 的数组 arrINDEX1$(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$(echo ${arr[0]})将数组 arr 的第一个元素索引为 0赋值给变量 INDEX1。INDEX2$(echo ${arr[1]})将数组 arr 的第二个元素索引为 1赋值给变量 INDEX2。INDEX3$(echo ${arr[2]})将数组 arr 的第三个元素索引为 2赋值给变量 INDEX3。
通过这种方式变量 INDEX1、INDEX2 和 INDEX3 将分别包含数组 arr 中对应索引位置的值。
24、批量修改文件名
示例
# 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 结尾的文件并将文件名进行修改。
for file in $(ls *html)使用 *html 通配符来查找当前目录下以 .html 结尾的文件并逐个进行处理。mv $ file bbs_$ {file#}使用 mv 命令将文件名修改为 bbs 后再加上原文件名第一个下划线后的部分。${file#_} 是一种字符串截取的方式表示获取变量 file 中第一个下划线后的部分。 替代方法1mv $file $(echo $file |sed -r s/*(_.* )/bbs\1/)使用 sed 命令进行正则表达式的替换操作将文件名中的第一个下划线及其后的部分替换为 bbs_ 加上对应的部分。替代方法2mv $ 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 结尾的文件并将这些文件的文件名进行修改。
. -maxdepth 1 -name “*html”使用 find 命令在当前目录下查找满足以下条件的文件 -maxdepth 1仅在当前目录进行查找不递归查找子目录。-name “*html”文件名以 .html 结尾。 for file in $(find . -maxdepth 1 -name “*html”)将查找到的文件列表循环处理。mv $ file bbs_$ {file#}使用 mv 命令将文件名修改为 bbs 后再加上原文件名中第一个下划线后的部分。${file#_} 是一种字符串截取的方式表示获取变量 file 中第一个下划线后的部分。 例如文件名为 prefix_filename.html那么 ${file#*_} 的值就是 filename.html然后将文件名修改为 bbs_filename.html。
这段代码的目的是在当前目录下查找以 .html 结尾的文件并将这些文件的文件名批量修改为以 bbs_ 开头并保留原文件名中第一个下划线后的部分。
方法3
# rename article bbs *.html这段代码使用了 rename 命令对当前目录下以 .html 结尾的文件进行批量重命名。
rename 命令用于批量重命名文件名中的指定部分。article 是要被替换的部分bbs 是替换后的部分。*.html 是要进行重命名操作的文件匹配模式表示当前目录下所有以 .html 结尾的文件。
这段代码的目的是将当前目录下以 .html 结尾的文件名中的 article 替换为 bbs实现文件名的批量重命名操作。
25、统计当前目录中以.html结尾的文件总大
方法1
# find . -name *.html -exec du -k {} \; |awk {sum$1}END{print sum}这段代码使用了find命令、du命令和awk命令来计算当前目录下以.html结尾的文件的总大小以KB为单位。
find . -name “*.html”使用find命令在当前目录及其子目录下查找文件名以.html结尾的文件。-exec du -k {} ;对于每个找到的文件使用du -k命令以KB为单位显示文件大小。通过-exec选项和{}占位符将找到的文件传递给du命令进行处理。|使用管道pipe将du命令的输出传递给下一个命令。awk ‘{sum$1}END{print sum}’使用awk命令对du命令的输出进行处理计算文件大小的总和。awk命令中的代码逐行读取du命令的输出并将每一行的第一个字段文件大小累加到变量sum中。最后在处理完所有行后在END部分使用print sum打印出总和。
这段代码的目的是计算当前目录下以.html结尾的文件的总大小以KB为单位。
方法2
for size in $(ls -l *.html | awk {print $5}); do # 获取当前目录下以 .html 结尾的文件的大小列表sum$(($sum$size)) # 对每个文件的大小进行累加
done
echo $sum # 打印所有文件大小的总和这段代码的作用是计算当前目录下以 .html 结尾的文件的总大小以字节为单位。
ls -l *.html | awk ‘{print $5}’使用 ls -l 命令获取当前目录下以 .html 结尾的文件的详细列表并通过管道将结果传递给 awk 命令。awk ‘{print $5}’ 表示只输出每行的第五个字段文件大小。for size in $(ls -l *.html | awk ‘{print $5}’)将获取到的文件大小列表逐个赋值给变量 size 进行循环处理。sum$ (($ sum$ size))将每个文件的大小累加到变量 sum 中。$ sum$ size 表示将变量 sum 和 size 的值相加。$((…)) 是一种算术表达式的写法。echo $sum打印所有文件大小的总和。
这段代码的目的是计算当前目录下以 .html 结尾的文件的总大小以字节为单位将每个文件的大小累加到变量 sum 中并最后打印出总和。
26、扫描主机端口状态
#!/bin/bash
HOST$1 # 获取第一个命令行参数作为主机名或 IP 地址
PORT22 25 80 8080 # 定义要检测的端口列表for PORT in $PORT; do # 遍历端口列表if echo /dev/null /dev/tcp/$HOST/$PORT; then # 使用 /dev/tcp 文件系统尝试与指定的主机和端口建立 TCP 连接echo $PORT open # 如果 TCP 连接成功则输出端口为开放状态elseecho $PORT close # 如果 TCP 连接失败则输出端口为关闭状态fi
done这段代码的作用是检测指定主机的一些常见端口是否开放。
#!/bin/bash指定该脚本以 Bash 解释器运行。HOST$1将第一个命令行参数赋值给变量 HOST表示要检测的主机名或 IP 地址。PORT“22 25 80 8080”定义要检测的端口列表包括 22、25、80 和 8080。for PORT in $PORT; do遍历端口列表。if echo /dev/null /dev/tcp/$ HOST/$PORT; then使用 /dev/tcp 文件系统尝试与指定的主机和端口建立 TCP 连接。通过重定向输入输出到 /dev/null 来实现静默连接的效果。echo “$PORT open”如果 TCP 连接成功则输出该端口为开放状态。echo “$PORT close”如果 TCP 连接失败则输出该端口为关闭状态。
这段代码的目的是遍历指定主机的端口列表并尝试与每个端口建立 TCP 连接通过输出端口状态来告知该端口是否开放。
27、Expect实现SSH免交互执行命令
Expect是一个自动交互式应用程序的工具如telnetftppasswd等。
需先安装expect软件包。
方法1EOF标准输出作为expect标准输入
#!/bin/bash
USERroot # 设置要登录的远程主机的用户名
PASS123.com # 设置远程主机用户的登录密码
IP192.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 远程登录到指定主机并执行一些操作。
USERroot将要登录的远程主机的用户名设置为 root。PASS123.com将远程主机用户的登录密码设置为 123.com。IP192.168.1.120设置远程主机的 IP 地址为 192.168.1.120。
在 expect 命令的使用过程中
set timeout 30设置超时时间为 30 秒用于控制登录的等待时间。spawn ssh U S E R USER USERIP使用 spawn 命令启动 ssh 进程进行远程登录连接。expect 块中使用模式匹配来等待特定的交互信息并根据不同的提示进行相应的操作。send 命令用于向程序发送输入信息完成自动化交互。$1 是一个变量它被发送给远程主机以执行特定操作。expect eof等待所有交互完成后终止 expect 脚本。
这段代码的目的是使用 expect 实现自动化登录远程主机并在登录后执行指定的操作。
方法2
#!/bin/bash
USERroot # 设置要登录的远程主机的用户名
PASS123.com # 设置远程主机的登录密码
IP192.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 登录到指定主机并执行特定命令的自动化操作。
USERroot将要登录的远程主机的用户名设置为 root。PASS123.com将远程主机的登录密码设置为 123.com。IP192.168.1.120设置远程主机的 IP 地址为 192.168.1.120。
在 expect -c 命令中
spawn ssh $ USER$IP使用 spawn 命令启动 ssh 进程进行远程登录连接。expect 块中使用模式匹配来等待特定的交互信息并根据不同的提示进行相应的操作。send 命令用于向程序发送输入信息完成自动化交互。“(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” 命令退出登录。exp_continue使 expect 继续等待下一个匹配。
这段代码的目的是通过 expect 实现自动化登录远程主机并在登录后执行特定命令如查看磁盘使用情况并最后退出登录。
28、批量修改服务器用户密码
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_INFOold_pass.txt # 存储旧密码信息的文件路径
NEW_INFOnew_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 2229、打印九九乘法口诀
for ((i1;i9;i)); do # 外层循环控制行数从 1 到 9for ((j1;ji;j)); do # 内层循环控制每行的乘法表达式从 1 到当前行数result$(($i*$j)) # 计算乘法结果echo -n $j*$i$result # 打印乘法表达式和结果不换行doneecho # 内层循环结束后换行
done这段代码的作用是打印一个简单的乘法表从 1 到 9按行输出。
在外层循环中i 控制当前行数从 1 到 9 逐渐增加。
在内层循环中j 控制每行的乘法表达式从 1 到当前行数 逐渐增加。
在每次内层循环中计算乘法结果 result 的值并使用 echo -n 打印乘法表达式和结果不换行。
内层循环结束后使用 echo 单独打印一个换行符换行后进入下一行的循环。
这段代码的输出结果是一个九九乘法表。
30、斐波那契数列
#!/bin/bashecho 请输入斐波那契数列的长度
read length # 获取用户输入的斐波那契数列长度# 初始化前两个斐波那契数
num10 # 第一个斐波那契数为 0
num21 # 第二个斐波那契数为 1# 输出前两个数
echo 斐波那契数列的前 $length 个数为
echo -n $num1 $num2 # 输出第一个和第二个斐波那契数# 循环计算并输出斐波那契数列
for ((i2;i$length;i))
dosum$(($num1 $num2)) # 计算下一个斐波那契数echo -n $sum # 输出计算得到的斐波那契数num1$num2 # 更新第一个斐波那契数为当前的第二个斐波那契数num2$sum # 更新第一个斐波那契数为当前的计算结果
doneecho # 输出换行符使结果美观这段代码的作用是根据用户输入的长度生成并输出相应长度的斐波那契数列。
echo “请输入斐波那契数列的长度”提示用户输入斐波那契数列的长度。read length将用户输入的长度保存到变量 length 中。
通过循环计算斐波那契数列并输出结果
num1 和 num2 分别用于保存当前计算的斐波那契数列的前两个数。使用 echo -n 输出前两个数。利用循环计算出剩余的斐波那契数并使用 echo -n 输出结果。在每次循环中更新 num1 和 num2 的值并继续计算下一个斐波那契数。