小白成长之路-Linux Shell脚本练习

题目一:系统详细信息收集与报告脚本

编写一个名为 system_info_gather.sh 的脚本,实现以下功能:

  1. 收集系统的以下详细信息:
  • 操作系统的发行版名称和版本号。

  • CPU 的型号、核心数量以及当前的频率。

  • 内存的总量以及当前的使用量。

  • 硬盘的分区信息,包括每个分区的大小、已使用空间和文件系统类型。

  • 系统的启动时间以及当前的运行时长。

  1. 将这些信息整理成一个清晰易读的格式,并输出到一个名为 system_report.txt 的文件中。同时,在脚本执行过程中,每收集到一项信息,就在终端上实时显示一个简短的提示信息,说明正在收集该项信息。
bash 复制代码
#!/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}"

验证:

bash 复制代码
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.shnetwork_config_restore.sh 的配对脚本:

  1. network_config_backup.sh 脚本的功能:
  • 备份当前系统的网络配置文件,包括但不限于 /etc/network/interfaces(或者适用于你所在系统的网络配置文件)、DHCP 配置文件(如果有)以及任何与网络相关的自定义脚本或配置片段。

  • 将这些备份文件压缩成一个以当前日期命名的归档文件,存储在 /backup/network_config/ 目录下(如果该目录不存在,则先创建它)。

bash 复制代码
#!/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"
  1. network_config_restore.sh 脚本的功能:
  • 接受一个归档文件作为参数(假设是之前备份的网络配置归档文件)。

  • 解压该归档文件,并将其中的配置文件恢复到原位置,覆盖现有配置(在恢复之前,最好有一个确认提示,以防止误操作)。

bash 复制代码
#!/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 的脚本,完成以下任务:

  1. 接受一个用户列表文件(每行一个用户名)作为参数。
  2. 对于列表中的每个用户:
  • 检查该用户是否存在,如果不存在,则在终端输出提示信息并跳过该用户。

  • 如果用户存在,检查其是否属于一个名为 special_group 的用户组(假设这个组与某些特殊权限相关),如果不属于,则将其添加到该组中。

  • 检查该用户对一个指定目录(例如 /data/shared/)的访问权限,如果没有读取和写入权限,则赋予相应权限(确保使用最安全的方式设置权限,例如只赋予必要的最小权限)。

bash 复制代码
#!/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 的脚本,实现以下功能:

  1. 接受一个服务名称列表文件(每行一个服务名称)作为参数。
  2. 对于列表中的每个服务:
  • 检查该服务的运行状态。如果服务正在运行,则记录其运行状态信息(例如进程 ID、占用的内存等,如果可以获取的话)到一个日志文件 /var/log/service_monitor.log 中。

  • 如果服务未运行,则尝试自动启动它,并在日志文件中记录启动的时间和结果(成功或失败)。

  1. 每隔一段时间(例如 10 分钟)重复上述检查和操作,持续运行。
bash 复制代码
#!/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 复制代码
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 的脚本,完成以下任务:

  1. 分析系统的一个关键应用程序的日志文件(假设日志文件路径为 /var/log/app.log),找出在过去一周内出现次数最多的前 5 种错误类型(假设错误类型可以通过日志中的特定关键字或格式来区分)。
  2. 对于每种错误类型,统计其出现的次数,并生成一个详细的报告,包括错误类型描述、出现次数以及在日志文件中出现的相关示例行(至少列出 3 个示例行)。
  3. 将这个报告输出到一个名为 log_analysis_report.txt 的文件中,并且在报告的开头包含本次分析的时间范围和日志文件的基本信息(例如日志文件大小、包含的日志行数等)。
bash 复制代码
#!/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"
相关推荐
A小辣椒1 天前
TShark:Wireshark CLI 功能
linux
A小辣椒1 天前
TShark:基础知识
linux
AlfredZhao1 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao2 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334662 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪2 天前
linux 拷贝文件或目录到指定的位置
linux
大树883 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质3 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush43 天前
嵌入式linux学习记录十四、术语
linux·嵌入式