题目一:系统详细信息收集与报告脚本
编写一个名为 system_info_gather.sh
的脚本,实现以下功能:
- 收集系统的以下详细信息:
- 操作系统的发行版名称和版本号。
- CPU 的型号、核心数量以及当前的频率。
- 内存的总量以及当前的使用量。
- 硬盘的分区信息,包括每个分区的大小、已使用空间和文件系统类型。
- 系统的启动时间以及当前的运行时长。
- 将这些信息整理成一个清晰易读的格式,并输出到一个名为
system_report.txt
的文件中。同时,在脚本执行过程中,每收集到一项信息,就在终端上实时显示一个简短的提示信息,说明正在收集该项信息。
#!/bin/bash
# 创建报告文件
REPORT_FILE="system_report.txt"
echo "正在生成系统报告..."
echo > "${REPORT_FILE}" # 清空文件
# 显示进度信息
progress() {
echo "正在收集$1信息中..."
}
#追加到文件中
addText() {
if [ $? -eq 0 ]; then
tee -a "$REPORT_FILE"
else
echo "获取信息失败" | tee -a "$REPORT_FILE"
fi
}
# 操作系统信息
progress "操作系统"
os_info=$(grep -E '^NAME=|^VERSION_ID=' /etc/os-release 2>/dev/null | sort -r)
name=$(echo "$os_info" | grep "^NAME=" | head -n1 | cut -d'"' -f2)
version=$(echo "$os_info" | grep "^VERSION_ID=" | head -n1 | cut -d'"' -f2)
echo "系统名称: $name, 版本: $version" | addText
# CPU信息
progress "CPU信息"
cpuType=$(grep "model name" /proc/cpuinfo | uniq | cut -d":" -f2 | xargs)
cpuCoreNum=$(grep -c "^processor" /proc/cpuinfo)
cpuFrequency=$(grep "cpu MHz" /proc/cpuinfo | uniq | cut -d":" -f2 | xargs | awk '{printf "%.0f MHz", $1}')
{
echo ""
echo "======= CPU 信息 ======="
echo "型号: ${cpuType}"
echo "核心数: ${cpuCoreNum}"
echo "频率: ${cpuFrequency}"
} | addText
# 内存信息
progress "内存信息"
memorySum=$(grep MemTotal /proc/meminfo | awk '{print $2}')
memoryAble=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
memoryUsed=$(( memorySum - memoryAble ))
# 转换为GB (保留2位小数)
memorySumGB=$(echo "scale=2; ${memorySum}/1024/1024" | bc)
memoryUsedGB=$(echo "scale=2; ${memoryUsed}/1024/1024" | bc)
{
echo ""
echo "======= 内存信息 ======="
printf "总内存: %.2f GB (%d kB)\n" "${memorySumGB}" "${memorySum}"
printf "已使用: %.2f GB (%d kB)\n" "${memoryUsedGB}" "${memoryUsed}"
printf "可用内存: %.2f GB (%d kB)\n" "$(echo "scale=2; ${memoryAble}/1024/1024" | bc)" "${memoryAble}"
} | addText
# 磁盘信息
progress "磁盘分区"
disk_info=$(df -Th)
{
echo ""
echo "======= 磁盘分区信息 ======="
echo "${disk_info}"
} | addText
# 系统启动信息
progress "系统启动"
start_time=$(date -d "now - $(awk '{printf "%.0f", $1}' /proc/uptime) seconds" +"%Y-%m-%d %H:%M:%S")
up_seconds=$(awk '{printf "%.0f", $1}' /proc/uptime)
days=$(( up_seconds / 86400 ))
hours=$(( (up_seconds % 86400) / 3600 ))
minutes=$(( (up_seconds % 3600) / 60 ))
{
echo ""
echo "======= 系统启动信息 ======="
echo "启动时间: ${start_time}"
echo "运行时长: ${days}天 ${hours}小时 ${minutes}分钟"
echo ""
} | addText
# 完成提示
echo ""
echo "系统信息收集完成!报告已保存至: ${REPORT_FILE}"
验证:
cat system_report.txt
系统名称: Rocky Linux, 版本: 8.10
======= CPU 信息 =======
型号: Intel(R) Core(TM) i5-10200H CPU @ 2.40GHz
核心数: 2
频率: 2400 MHz
======= 内存信息 =======
总内存: 3.54 GB (3720852 kB)
已使用: 1.27 GB (1335324 kB)
可用内存: 2.27 GB (2385528 kB)
======= 磁盘分区信息 =======
文件系统 类型 容量 已用 可用 已用% 挂载点
devtmpfs devtmpfs 1.8G 0 1.8G 0% /dev
tmpfs tmpfs 1.8G 0 1.8G 0% /dev/shm
tmpfs tmpfs 1.8G 33M 1.8G 2% /run
tmpfs tmpfs 1.8G 0 1.8G 0% /sys/fs/cgroup
/dev/mapper/rl-root xfs 17G 6.2G 11G 36% /
/dev/sda1 xfs 1014M 275M 740M 28% /boot
tmpfs tmpfs 364M 20K 364M 1% /run/user/0
======= 系统启动信息 =======
启动时间: 2025-06-07 18:31:00
运行时长: 0天 6小时 43分钟
题目二:网络配置备份与恢复脚本
创建一个名为 network_config_backup.sh
和 network_config_restore.sh
的配对脚本:
network_config_backup.sh
脚本的功能:
- 备份当前系统的网络配置文件,包括但不限于 /etc/network/interfaces
(或者适用于你所在系统的网络配置文件)、DHCP 配置文件(如果有)以及任何与网络相关的自定义脚本或配置片段。
- 将这些备份文件压缩成一个以当前日期命名的归档文件,存储在 /backup/network_config/
目录下(如果该目录不存在,则先创建它)。
#!/bin/bash
# 设置备份目录
BACKUP_DIR="/backup/network_config"
# 获取当前日期,格式为 YYYY-MM-DD
DATE=$(date +%F)
# 创建备份目录(如果不存在)
if [ ! -d "$BACKUP_DIR" ]; then
mkdir -p "$BACKUP_DIR"
if [ $? -ne 0 ]; then
echo "创建备份目录失败,请检查权限或磁盘空间。"
exit 1
fi
fi
# 定义要备份的网络配置文件
declare -a CONFIG_FILES=(
"/etc/network/interfaces"
"/etc/dhcp/dhcpd.conf"
"/etc/network/interfaces.d/"
"/etc/netplan/"
"/etc/network/if-up.d/"
"/etc/network/if-down.d/"
)
# 定义要备份的自定义脚本或配置片段
declare -a CUSTOM_FILES=(
"/etc/my_custom_network_script.sh"
"/etc/my_custom_network_config.conf"
)
# 创建临时备份目录
TEMP_DIR=$(mktemp -d)
if [ $? -ne 0 ]; then
echo "创建临时目录失败。"
exit 1
fi
# 复制网络配置文件到临时目录
for file in "${CONFIG_FILES[@]}"; do
if [ -e "$file" ]; then
cp -r "$file" "$TEMP_DIR"
if [ $? -ne 0 ]; then
echo "复制文件 $file 失败。"
exit 1
fi
fi
done
# 复制自定义脚本或配置片段到临时目录
for file in "${CUSTOM_FILES[@]}"; do
if [ -e "$file" ]; then
cp -r "$file" "$TEMP_DIR"
if [ $? -ne 0 ]; then
echo "复制文件 $file 失败。"
exit 1
fi
fi
done
# 压缩临时目录为归档文件
ARCHIVE_FILE="$BACKUP_DIR/network_config_backup_$DATE.tar.gz"
tar -czf "$ARCHIVE_FILE" -C "$TEMP_DIR" .
if [ $? -ne 0 ]; then
echo "压缩备份文件失败。"
exit 1
fi
# 清理临时目录
rm -rf "$TEMP_DIR"
# 输出备份成功信息
echo "网络配置文件备份成功,备份文件存储在:$ARCHIVE_FILE"
network_config_restore.sh
脚本的功能:
- 接受一个归档文件作为参数(假设是之前备份的网络配置归档文件)。
- 解压该归档文件,并将其中的配置文件恢复到原位置,覆盖现有配置(在恢复之前,最好有一个确认提示,以防止误操作)。
#!/bin/bash
# 检查是否提供了归档文件参数
if [ $# -eq 0 ]; then
echo "用法: $0 <归档文件路径>"
exit 1
fi
ARCHIVE_FILE="$1"
# 检查归档文件是否存在
if [ ! -f "$ARCHIVE_FILE" ]; then
echo "错误:归档文件 $ARCHIVE_FILE 不存在。"
exit 1
fi
# 提示用户是否要解压归档文件
read -p "是否要解压该归档文件?(y表示是,其他字符表示否): " doing
# 判断用户输入
if [ "$doing" == "y" ]; then
# 提示用户输入解压路径
read -p "输入要解压的目录: " path
# 检查路径是否为空
if [ -z "$path" ]; then
echo "错误:未指定解压目录。"
exit 1
fi
# 创建目录(如果不存在)
if [ ! -d "$path" ]; then
echo "创建目录: $path"
mkdir -p "$path"
if [ $? -ne 0 ]; then
echo "错误:无法创建目录 $path"
exit 1
fi
fi
echo "正在解压 $ARCHIVE_FILE 到 $path ..."
# 执行解压操作
tar -xzvf "$ARCHIVE_FILE" -C "$path"
if [ $? -eq 0 ]; then
echo "解压归档文件成功。"
echo "解压内容:"
ls -l "$path"
else
echo "解压归档文件失败。"
exit 1
fi
else
echo "操作已取消。"
exit 0
fi
题目三:用户权限管理脚本
编写一个名为 user_permission_adjust.sh
的脚本,完成以下任务:
- 接受一个用户列表文件(每行一个用户名)作为参数。
- 对于列表中的每个用户:
- 检查该用户是否存在,如果不存在,则在终端输出提示信息并跳过该用户。
- 如果用户存在,检查其是否属于一个名为 special_group
的用户组(假设这个组与某些特殊权限相关),如果不属于,则将其添加到该组中。
- 检查该用户对一个指定目录(例如 /data/shared/
)的访问权限,如果没有读取和写入权限,则赋予相应权限(确保使用最安全的方式设置权限,例如只赋予必要的最小权限)。
#!/bin/bash
# 定义特殊组和目标目录
GROUP="special_group"
DIR="/data/shared"
USERLIST="$1"
# 检查目录是否存在
if [ ! -d "$DIR" ]; then
echo "目录不存在,正在创建..."
mkdir -p "$DIR"
if [ $? -ne 0 ]; then
echo "创建目录失败,请检查权限。"
exit 1
fi
fi
# 检查特殊组是否存在,如果不存在则创建
if ! getent group "$GROUP" &>/dev/null; then
echo "组 $GROUP 不存在,正在创建..."
groupadd "$GROUP"
if [ $? -ne 0 ]; then
echo "创建组 $GROUP 失败。"
exit 1
fi
fi
# 检查文件中的用户
for i in $(cat "$USERLIST"); do
# 检查用户是否存在
if ! id "$i" &>/dev/null; then
echo "用户 $i 不存在,跳过。"
continue
fi
# 检查用户是否属于 special_group
if ! groups "$i" | grep -q "\b$GROUP\b"; then
echo "用户 $i 不属于 $GROUP,正在添加..."
usermod -aG "$GROUP" "$i"
if [ $? -ne 0 ]; then
echo "将用户 $i 添加到 $GROUP 失败。"
continue
fi
fi
# 检查用户权限
if [ ! -r "$DIR" ] || [ ! -w "$DIR" ]; then
echo "用户 $i 对 $DIR 没有读取或写入权限,正在设置权限..."
setfacl -m u:"$i":rwX "$DIR"
if [ $? -ne 0 ]; then
echo "为用户 $i 设置权限失败。"
continue
fi
fi
echo "用户 $i 的权限已调整完成。"
done
验证:
题目四:服务状态监控与自动重启脚本
创建一个名为 service_monitor.sh
的脚本,实现以下功能:
- 接受一个服务名称列表文件(每行一个服务名称)作为参数。
- 对于列表中的每个服务:
- 检查该服务的运行状态。如果服务正在运行,则记录其运行状态信息(例如进程 ID、占用的内存等,如果可以获取的话)到一个日志文件 /var/log/service_monitor.log
中。
- 如果服务未运行,则尝试自动启动它,并在日志文件中记录启动的时间和结果(成功或失败)。
- 每隔一段时间(例如 10 分钟)重复上述检查和操作,持续运行。
#!/bin/bash
# 检查是否提供了服务列表文件作为参数
if [ $# -ne 1 ]; then
echo "用法: $0 <服务名称列表文件>"
exit 1
fi
# 获取服务列表文件路径
SERVICE_LIST_FILE=$1
# 检查服务列表文件是否存在
if [ ! -f "$SERVICE_LIST_FILE" ]; then
echo "错误:服务列表文件 $SERVICE_LIST_FILE 不存在。"
exit 1
fi
# 定义日志文件路径
LOG_FILE="/var/log/service_monitor.log"
# 检查日志文件是否存在,如果不存在则创建
if [ ! -f "$LOG_FILE" ]; then
touch "$LOG_FILE"
if [ $? -ne 0 ]; then
echo "创建日志文件失败,请检查权限。"
exit 1
fi
fi
# 定义检查间隔时间(秒)
INTERVAL=600 # 10 分钟
echo "脚本开始运行..." >> "$LOG_FILE"
# 主循环
while true; do
# 读取服务列表文件,逐行处理每个服务
for service in $(cat "$SERVICE_LIST_FILE"); do
# 检查服务是否正在运行
if systemctl is-active --quiet "$service"; then
# 服务正在运行,记录运行状态信息
echo "$(date '+%Y-%m-%d %H:%M:%S') - 服务 $service 正在运行。" >> "$LOG_FILE"
# 获取进程 ID 和占用的内存
pid=$(pgrep -o "$service")
if [ -n "$pid" ]; then
mem=$(ps -o rss= -p "$pid")
echo " 进程 ID: $pid, 占用内存: $mem KB" >> "$LOG_FILE"
fi
else
# 服务未运行,尝试自动启动
echo "$(date '+%Y-%m-%d %H:%M:%S') - 服务 $service 未运行,正在尝试启动..." >> "$LOG_FILE"
systemctl start "$service"
if systemctl is-active --quiet "$service"; then
echo " 服务 $service 启动成功。" >> "$LOG_FILE"
else
echo " 服务 $service 启动失败。" >> "$LOG_FILE"
fi
fi
done
# 等待指定的时间间隔
sleep "$INTERVAL"
done
验证
使用bash -x检查没有报错
bash -x service_monitor.sh servicelist.txt
+ '[' 1 -ne 1 ']'
+ SERVICE_LIST_FILE=servicelist.txt
+ '[' '!' -f servicelist.txt ']'
+ LOG_FILE=/var/log/service_monitor.log
+ '[' '!' -f /var/log/service_monitor.log ']'
+ INTERVAL=600
+ true
+ IFS=
+ read -r service
+ systemctl is-active --quiet sshd
++ date '+%Y-%m-%d %H:%M:%S'
+ echo '2025-06-08 06:24:05 - 服务 sshd 正在运行。'
++ pgrep -o sshd
+ pid=1040
+ '[' -n 1040 ']'
++ ps -o rss= -p 1040
+ mem=' 6980'
+ echo ' 进程 ID: 1040, 占用内存: 6980 KB'
+ IFS=
+ read -r service
+ systemctl is-active --quiet nginx
++ date '+%Y-%m-%d %H:%M:%S'
+ echo '2025-06-08 06:24:05 - 服务 nginx 正在运行。'
++ pgrep -o nginx
+ pid=295521
+ '[' -n 295521 ']'
++ ps -o rss= -p 295521
+ mem=' 2188'
+ echo ' 进程 ID: 295521, 占用内存: 2188 KB'
+ IFS=
+ read -r service
+ sleep 600
为了方便测试,我把时间改为10秒
题目五:系统日志分析与报告脚本
编写一个名为 log_analyzer.sh
的脚本,完成以下任务:
- 分析系统的一个关键应用程序的日志文件(假设日志文件路径为
/var/log/app.log
),找出在过去一周内出现次数最多的前 5 种错误类型(假设错误类型可以通过日志中的特定关键字或格式来区分)。 - 对于每种错误类型,统计其出现的次数,并生成一个详细的报告,包括错误类型描述、出现次数以及在日志文件中出现的相关示例行(至少列出 3 个示例行)。
- 将这个报告输出到一个名为
log_analysis_report.txt
的文件中,并且在报告的开头包含本次分析的时间范围和日志文件的基本信息(例如日志文件大小、包含的日志行数等)。
#!/bin/bash
# 定义日志文件路径
LOG_FILE="/var/log/app.log"
REPORT_FILE="log_analysis_report.txt"
DATE_RANGE=$(date -d "7 days ago" +%Y-%m-%d)
# 检查日志文件是否存在,如果不存在则创建
if [ ! -f "$LOG_FILE" ]; then
echo "日志文件 $LOG_FILE 不存在,正在创建空日志文件..."
touch "$LOG_FILE"
if [ $? -ne 0 ]; then
echo "创建日志文件失败,请检查权限。"
exit 1
fi
echo "日志文件已创建。"
fi
# 获取日志文件的基本信息
LOG_SIZE=$(du -sh "$LOG_FILE" | cut -f1)
LOG_LINES=$(wc -l < "$LOG_FILE")
# 写入报告文件的头部信息
echo "日志分析报告" > "$REPORT_FILE"
echo "分析时间范围:过去一周(从 $DATE_RANGE 至 $(date +%Y-%m-%d))" >> "$REPORT_FILE"
echo "日志文件路径:$LOG_FILE" >> "$REPORT_FILE"
echo "日志文件大小:$LOG_SIZE" >> "$REPORT_FILE"
echo "日志行数:$LOG_LINES" >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"
# 提取过去一周的日志内容
TEMP_LOG=$(mktemp)
grep -E "$(date -d "$DATE_RANGE" +%Y-%m-%d)" "$LOG_FILE" > "$TEMP_LOG"
# 分析错误类型
ERROR_TYPES=$(grep -oE 'ERROR: [A-Za-z0-9_ ]+' "$TEMP_LOG" | sort | uniq -c | sort -nr | head -5)
# 写入错误类型分析结果
echo "错误类型分析:" >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"
while IFS= read -r line; do
COUNT=$(echo "$line" | awk '{print $1}')
ERROR_TYPE=$(echo "$line" | awk '{$1=""; print $0}' | xargs)
echo "错误类型:$ERROR_TYPE" >> "$REPORT_FILE"
echo "出现次数:$COUNT" >> "$REPORT_FILE"
echo "示例行:" >> "$REPORT_FILE"
grep "$ERROR_TYPE" "$TEMP_LOG" | head -3 >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"
done <<< "$ERROR_TYPES"
# 清理临时文件
rm "$TEMP_LOG"
echo "报告已生成:$REPORT_FILE"