介绍
这个脚本是使用人工智能创建的,专门用于管理Linux系统虚拟内存的,因为前几天我彻底弃用宝塔面板,然后然而ACE面板并没有相应的虚拟内存管理工具,所以就只能依赖于脚本关闭了,毕竟手动关闭太麻烦了。然后我就使用通义千问生成脚本,终于在第四版达到了生产级。然后就是一些感慨,一年过去了,人工智能确实在变强,至少我见到的Github上Web项目的脚本的维护真的已经可以完全交给人工智能了。
脚本
#!/bin/bash
# =============================================================================
# 虚拟内存(Swap)管理脚本 v4 (生产级)
# =============================================================================
# 功能: 创建/删除/管理Linux系统swap空间
# 作者: 通义千问
# 版本: 4.0.0
# 日期: 2026-02-18
# =============================================================================
# 使用方法: sudo ./swap_manager.sh [命令] [参数]
# 示例: sudo ./swap_manager.sh on 4G
# =============================================================================
set -o pipefail
# -----------------------------------------------------------------------------
# 配置常量
# -----------------------------------------------------------------------------
SCRIPT_NAME=$(basename "$0")
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SWAP_FILE="/swapfile"
LOG_FILE="/var/log/swap_manager.log"
FSTAB_BACKUP_DIR="/var/backup/swap_manager"
MAX_SWAP_WAIT_SECONDS=60
MIN_DISK_FREE_PERCENT=15
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# -----------------------------------------------------------------------------
# 日志函数
# -----------------------------------------------------------------------------
init_log() {
mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null
touch "$LOG_FILE" 2>/dev/null || LOG_FILE="/tmp/swap_manager.log"
}
log() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" >> "$LOG_FILE" 2>/dev/null
}
log_info() { log "INFO" "$1"; }
log_warn() { log "WARN" "$1"; }
log_error() { log "ERROR" "$1"; }
# -----------------------------------------------------------------------------
# 初始化检查
# -----------------------------------------------------------------------------
init_check() {
init_log
log_info "========== 脚本启动 =========="
log_info "命令: $*"
# 检查root权限
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}错误: 请使用 sudo 运行此脚本${NC}"
echo "用法: sudo $SCRIPT_NAME [on|off|status|delete|swappiness|restore|help] [参数]"
log_error "非root用户尝试运行"
exit 1
fi
# 检查必要命令
local required_commands="swapon swapoff mkswap free df sed awk grep chmod chown"
for cmd in $required_commands; do
if ! command -v "$cmd" &> /dev/null; then
echo -e "${RED}错误: 缺少必要命令 '$cmd'${NC}"
log_error "缺少必要命令: $cmd"
exit 1
fi
done
# 创建备份目录
mkdir -p "$FSTAB_BACKUP_DIR" 2>/dev/null
log_info "初始化检查完成"
}
# -----------------------------------------------------------------------------
# 显示swap状态
# -----------------------------------------------------------------------------
show_status() {
echo -e "${GREEN}╔════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ 当前虚拟内存(Swap)状态 ║${NC}"
echo -e "${GREEN}╚════════════════════════════════════════╝${NC}"
echo ""
# Swap设备列表
echo -e "${CYAN}┌─ Swap设备列表 ─────────────────────────┐${NC}"
if swapon --show &>/dev/null; then
local swap_count=$(swapon --show --noheadings 2>/dev/null | wc -l)
if [ "$swap_count" -gt 0 ]; then
swapon --show --bytes 2>/dev/null | while read -r line; do
echo -e " ${GREEN}✓${NC} $line"
done
else
echo -e " ${YELLOW}无活动的swap设备${NC}"
fi
else
echo -e " ${RED}无法获取swap信息${NC}"
fi
echo -e "${CYAN}└────────────────────────────────────────┘${NC}"
echo ""
# 内存使用情况
echo -e "${CYAN}┌─ 内存使用情况 ─────────────────────────┐${NC}"
if command -v free &>/dev/null; then
free -h 2>/dev/null | grep -i swap | while read -r line; do
echo " $line"
done
# 计算使用率
local swap_total=$(free | awk '/Swap/ {print $2}')
local swap_used=$(free | awk '/Swap/ {print $3}')
if [ "$swap_total" -gt 0 ] 2>/dev/null; then
local swap_percent=$((swap_used * 100 / swap_total))
echo ""
echo -e " Swap使用率: ${YELLOW}${swap_percent}%${NC}"
fi
else
echo -e " ${RED}free命令不可用${NC}"
fi
echo -e "${CYAN}└────────────────────────────────────────┘${NC}"
echo ""
# Swappiness值
echo -e "${CYAN}┌─ Swappiness配置 ───────────────────────┐${NC}"
if [ -f /proc/sys/vm/swappiness ]; then
local swappiness=$(cat /proc/sys/vm/swappiness 2>/dev/null)
echo -e " 当前值: ${YELLOW}${swappiness}${NC}"
echo -e " 说明: 0=避免swap, 60=默认, 100=积极使用"
else
echo -e " ${RED}无法读取swappiness值${NC}"
fi
echo -e "${CYAN}└────────────────────────────────────────┘${NC}"
echo ""
# Swap文件信息
echo -e "${CYAN}┌─ Swap文件信息 ─────────────────────────┐${NC}"
if [ -f "$SWAP_FILE" ]; then
local swap_size=$(ls -lh "$SWAP_FILE" 2>/dev/null | awk '{print $5}')
local swap_perms=$(ls -l "$SWAP_FILE" 2>/dev/null | awk '{print $1}')
local swap_owner=$(ls -l "$SWAP_FILE" 2>/dev/null | awk '{print $3":"$4}')
local swap_attr=$(lsattr "$SWAP_FILE" 2>/dev/null | awk '{print $1}')
echo -e " 路径: ${GREEN}$SWAP_FILE${NC}"
echo -e " 大小: $swap_size"
echo -e " 权限: $swap_perms"
echo -e " 所有者: $swap_owner"
echo -e " 属性: ${swap_attr:-无特殊属性}"
else
echo -e " ${YELLOW}Swap文件不存在${NC}"
fi
echo -e "${CYAN}└────────────────────────────────────────┘${NC}"
echo ""
# Fstab配置
echo -e "${CYAN}┌─ /etc/fstab配置 ───────────────────────┐${NC}"
if [ -f /etc/fstab ]; then
local fstab_swap=$(grep -E 'swap|swapfile' /etc/fstab 2>/dev/null)
if [ -n "$fstab_swap" ]; then
echo "$fstab_swap" | while read -r line; do
echo -e " ${GREEN}$line${NC}"
done
else
echo -e " ${YELLOW}无swap相关配置${NC}"
fi
else
echo -e " ${RED}/etc/fstab不存在${NC}"
fi
echo -e "${CYAN}└────────────────────────────────────────┘${NC}"
echo ""
log_info "状态检查完成"
}
# -----------------------------------------------------------------------------
# 验证大小格式
# -----------------------------------------------------------------------------
validate_size() {
local size="$1"
if [[ ! $size =~ ^[0-9]+[KkMmGg][Bb]?$ ]]; then
echo -e "${RED}错误: 无效的大小格式 '${size}'${NC}"
echo "请使用格式: 数字+单位 (如 2G, 4G, 512M, 1GB)"
log_error "无效的大小格式: $size"
exit 1
fi
}
# -----------------------------------------------------------------------------
# 转换大小为字节
# -----------------------------------------------------------------------------
size_to_bytes() {
local size="$1"
local num=$(echo "$size" | sed 's/[^0-9]//g')
local unit=$(echo "$size" | sed 's/[0-9]//g' | tr '[:lower:]' '[:upper:]' | sed 's/B$//')
case "$unit" in
G) echo $((num * 1024 * 1024 * 1024)) ;;
M) echo $((num * 1024 * 1024)) ;;
K) echo $((num * 1024)) ;;
*) echo $((num * 1024 * 1024 * 1024)) ;; # 默认GB
esac
}
# -----------------------------------------------------------------------------
# 检查文件系统类型
# -----------------------------------------------------------------------------
check_filesystem() {
local target_path="$1"
local fs_type=$(df -T "$target_path" 2>/dev/null | awk 'NR==2 {print $2}')
log_info "文件系统类型: $fs_type"
# 不支持的文件系统
local unsupported_fs="nfs cifs smbfs fuse.sshfs tmpfs ramfs"
for fs in $unsupported_fs; do
if [ "$fs_type" = "$fs" ] || [[ "$fs_type" == *"$fs"* ]]; then
echo -e "${RED}错误: 不支持在 '$fs_type' 文件系统上创建swap${NC}"
echo "Swap文件需要本地磁盘文件系统 (ext4, xfs, btrfs等)"
log_error "不支持的文件系统: $fs_type"
exit 1
fi
done
# 警告某些文件系统
if [ "$fs_type" = "btrfs" ]; then
echo -e "${YELLOW}警告: Btrfs文件系统可能需要特殊配置${NC}"
echo "建议: 使用 nodatacow 选项或考虑使用swap分区"
fi
echo "$fs_type"
}
# -----------------------------------------------------------------------------
# 检查磁盘空间
# -----------------------------------------------------------------------------
check_disk_space() {
local required_bytes="$1"
local mount_point="/"
# 获取可用空间(字节)
local available_bytes=$(df -B1 "$mount_point" 2>/dev/null | awk 'NR==2 {print $4}')
if [ -z "$available_bytes" ] || [ "$available_bytes" -eq 0 ]; then
echo -e "${RED}错误: 无法获取磁盘空间信息${NC}"
log_error "无法获取磁盘空间"
exit 1
fi
# 计算可用百分比
local total_bytes=$(df -B1 "$mount_point" 2>/dev/null | awk 'NR==2 {print $2}')
local free_percent=$((available_bytes * 100 / total_bytes))
# 检查最小可用空间
if [ "$free_percent" -lt "$MIN_DISK_FREE_PERCENT" ]; then
echo -e "${RED}错误: 磁盘可用空间不足 (${free_percent}%)${NC}"
echo "建议至少保留 ${MIN_DISK_FREE_PERCENT}% 的可用空间"
log_error "磁盘空间不足: ${free_percent}%"
exit 1
fi
# 检查是否足够创建swap(预留10%缓冲)
local required_with_buffer=$((required_bytes * 110 / 100))
if [ "$available_bytes" -lt "$required_with_buffer" ]; then
local available_gb=$((available_bytes / 1024 / 1024 / 1024))
local required_gb=$((required_with_buffer / 1024 / 1024 / 1024 + 1))
echo -e "${RED}错误: 磁盘空间不足${NC}"
echo " 可用空间: ${available_gb}G"
echo " 需要空间: ${required_gb}G (含10%缓冲)"
log_error "空间不足: 可用${available_bytes}字节, 需要${required_with_buffer}字节"
exit 1
fi
log_info "磁盘空间检查通过: 可用${available_bytes}字节, 需要${required_bytes}字节"
return 0
}
# -----------------------------------------------------------------------------
# 检查现有swap
# -----------------------------------------------------------------------------
check_existing_swap() {
local existing_count=$(swapon --show --noheadings 2>/dev/null | wc -l)
if [ "$existing_count" -gt 0 ]; then
echo -e "${YELLOW}注意: 系统已有 $existing_count 个swap设备${NC}"
swapon --show 2>/dev/null | while read -r line; do
echo -e " $line"
done
log_info "现有swap设备数: $existing_count"
else
log_info "无现有swap设备"
fi
return 0
}
# -----------------------------------------------------------------------------
# 等待swap关闭完成
# -----------------------------------------------------------------------------
wait_for_swapoff() {
local target_file="$1"
local max_wait="$MAX_SWAP_WAIT_SECONDS"
local waited=0
echo -e "${YELLOW}等待swap完全关闭...${NC}"
while [ $waited -lt $max_wait ]; do
if ! swapon --show 2>/dev/null | grep -q "$target_file"; then
log_info "swap在 ${waited}秒后成功关闭"
return 0
fi
sleep 1
waited=$((waited + 1))
# 每10秒显示进度
if [ $((waited % 10)) -eq 0 ]; then
echo -e " 已等待 ${waited}/${max_wait} 秒..."
fi
done
log_warn "等待swap关闭超时 (${max_wait}秒)"
return 1
}
# -----------------------------------------------------------------------------
# 备份fstab
# -----------------------------------------------------------------------------
backup_fstab() {
if [ ! -f /etc/fstab ]; then
log_warn "/etc/fstab不存在,跳过备份"
return 0
fi
local backup_file="${FSTAB_BACKUP_DIR}/fstab.backup.$(date +%Y%m%d_%H%M%S)"
if cp /etc/fstab "$backup_file" 2>/dev/null; then
echo -e "${GREEN}✓ 已备份 /etc/fstab 到 $backup_file${NC}"
log_info "fstab备份完成: $backup_file"
return 0
else
echo -e "${RED}✗ 备份 /etc/fstab 失败${NC}"
log_error "fstab备份失败"
return 1
fi
}
# -----------------------------------------------------------------------------
# 从备份恢复fstab
# -----------------------------------------------------------------------------
restore_fstab() {
echo -e "${CYAN}可用的fstab备份:${NC}"
local backups=$(ls -t "${FSTAB_BACKUP_DIR}"/fstab.backup.* 2>/dev/null)
if [ -z "$backups" ]; then
echo -e "${RED}未找到任何备份文件${NC}"
return 1
fi
echo "$backups" | head -10 | nl
echo ""
read -p "选择要恢复的备份编号 (1-10, 或按回车取消): " choice
if [ -z "$choice" ]; then
echo "操作已取消"
return 0
fi
local selected=$(echo "$backups" | head -10 | sed -n "${choice}p")
if [ -z "$selected" ]; then
echo -e "${RED}无效的选择${NC}"
return 1
fi
echo -e "${YELLOW}将恢复: $selected${NC}"
read -p "确认恢复?(y/n): " confirm
confirm=$(echo "$confirm" | tr '[:upper:]' '[:lower:]')
if [ "$confirm" = "y" ]; then
if cp "$selected" /etc/fstab 2>/dev/null; then
echo -e "${GREEN}✓ fstab已恢复${NC}"
log_info "fstab已从 $selected 恢复"
return 0
else
echo -e "${RED}✗ 恢复失败${NC}"
log_error "fstab恢复失败"
return 1
fi
else
echo "操作已取消"
return 0
fi
}
# -----------------------------------------------------------------------------
# 关闭swap
# -----------------------------------------------------------------------------
swap_off() {
echo -e "${YELLOW}正在关闭虚拟内存(swap)...${NC}"
log_info "开始关闭swap"
# 检查当前swap使用情况
local swap_total=$(free | awk '/Swap/ {print $2}')
local swap_used=$(free | awk '/Swap/ {print $3}')
if [ "$swap_total" -gt 0 ] 2>/dev/null && [ "$swap_used" -gt 0 ] 2>/dev/null; then
local swap_percent=$((swap_used * 100 / swap_total))
echo -e "${YELLOW}当前swap使用率: ${swap_percent}% (${swap_used}KB / ${swap_total}KB)${NC}"
if [ "$swap_percent" -gt 80 ]; then
echo -e "${RED}警告: swap使用率过高${NC}"
echo -e "${YELLOW}建议先关闭占用swap的程序${NC}"
echo -e "${CYAN}尝试清理页面缓存...${NC}"
sync
echo 3 > /proc/sys/vm/drop_caches 2>/dev/null
sleep 2
fi
echo ""
read -p "是否继续?(y/n): " confirm
confirm=$(echo "$confirm" | tr '[:upper:]' '[:lower:]')
if [ "$confirm" != "y" ]; then
echo "操作已取消"
log_info "用户取消关闭swap"
return 0
fi
fi
# 关闭所有swap
echo -e "${CYAN}执行 swapoff -a...${NC}"
swapoff -a 2>/dev/null
local swapoff_result=$?
if [ $swapoff_result -eq 0 ]; then
# 等待并验证
if wait_for_swapoff "$SWAP_FILE"; then
echo -e "${GREEN}✓ 虚拟内存已成功关闭${NC}"
log_info "swap关闭成功"
else
echo -e "${YELLOW}⚠ swapoff完成但检测到swap仍活动${NC}"
log_warn "swap关闭后仍有活动swap"
fi
else
echo -e "${YELLOW}swapoff -a 失败,尝试单独关闭...${NC}"
swapoff "$SWAP_FILE" 2>/dev/null
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ 虚拟内存已成功关闭${NC}"
log_info "swap单独关闭成功"
else
echo -e "${RED}✗ 关闭虚拟内存失败${NC}"
echo -e "${CYAN}当前活动的swap设备:${NC}"
swapon --show 2>/dev/null
log_error "swap关闭失败"
return 1
fi
fi
echo ""
show_status
return 0
}
# -----------------------------------------------------------------------------
# 开启swap
# -----------------------------------------------------------------------------
swap_on() {
local swap_size="$1"
log_info "开始开启swap, 大小: ${swap_size:-现有}"
echo -e "${YELLOW}正在开启虚拟内存(swap)...${NC}"
echo ""
# 检查现有swap
check_existing_swap
# 如果指定了大小,创建新的swap文件
if [ -n "$swap_size" ]; then
echo -e "${CYAN}将创建 ${swap_size} 的swap文件${NC}"
# 检查文件系统
check_filesystem "/"
echo ""
# 检查磁盘空间
local required_bytes=$(size_to_bytes "$swap_size")
check_disk_space "$required_bytes"
echo ""
# 检查swap文件是否已存在
if [ -f "$SWAP_FILE" ]; then
echo -e "${YELLOW}警告: $SWAP_FILE 已存在${NC}"
read -p "是否删除并重新创建?(y/n): " confirm
confirm=$(echo "$confirm" | tr '[:upper:]' '[:lower:]')
if [ "$confirm" = "y" ]; then
echo -e "${CYAN}关闭现有swap...${NC}"
swapoff "$SWAP_FILE" 2>/dev/null
rm -f "$SWAP_FILE"
echo -e "${GREEN}✓ 已删除旧swap文件${NC}"
log_info "删除旧swap文件"
else
echo "操作已取消"
log_info "用户取消创建swap"
return 0
fi
fi
# 创建swap文件
echo -e "${CYAN}正在创建swap文件,请稍候...${NC}"
log_info "开始创建swap文件: $swap_size"
# 尝试fallocate
fallocate -l "$swap_size" "$SWAP_FILE" 2>/dev/null
local fallocate_result=$?
if [ $fallocate_result -ne 0 ] || [ ! -f "$SWAP_FILE" ] || [ ! -s "$SWAP_FILE" ]; then
echo -e "${YELLOW}fallocate不可用或失败,使用dd方法...${NC}"
log_info "fallocate失败,使用dd"
local num=$(echo "$swap_size" | sed 's/[^0-9]//g')
local unit=$(echo "$swap_size" | sed 's/[0-9]//g' | tr '[:lower:]' '[:upper:]' | sed 's/B$//')
local bs=1024
local count
case "$unit" in
G) count=$((num * 1024 * 1024)) ;;
M) count=$((num * 1024)) ;;
K) count=$num ;;
*) count=$((num * 1024 * 1024)) ;;
esac
dd if=/dev/zero of="$SWAP_FILE" bs=$bs count=$count status=progress 2>&1 | tail -5
fi
# 验证文件创建
if [ ! -f "$SWAP_FILE" ]; then
echo -e "${RED}✗ Swap文件创建失败${NC}"
log_error "swap文件创建失败"
return 1
fi
# 设置权限和所有者
chmod 600 "$SWAP_FILE"
chown root:root "$SWAP_FILE"
echo -e "${GREEN}✓ Swap文件创建完成${NC}"
log_info "swap文件创建完成: $(ls -lh $SWAP_FILE)"
# 格式化为swap
echo -e "${CYAN}正在格式化swap...${NC}"
mkswap "$SWAP_FILE" 2>&1 | tail -3
if [ $? -ne 0 ]; then
echo -e "${RED}✗ swap格式化失败${NC}"
log_error "swap格式化失败"
rm -f "$SWAP_FILE"
return 1
fi
echo -e "${GREEN}✓ Swap格式化完成${NC}"
else
# 使用现有swap文件
if [ ! -f "$SWAP_FILE" ]; then
echo -e "${RED}错误: $SWAP_FILE 不存在${NC}"
echo "请先使用 'sudo $SCRIPT_NAME on [大小]' 创建swap文件"
log_error "swap文件不存在"
return 1
fi
echo -e "${CYAN}使用现有swap文件: $SWAP_FILE${NC}"
fi
# 启用swap
echo -e "${CYAN}正在启用swap...${NC}"
swapon "$SWAP_FILE" 2>/dev/null
local swapon_result=$?
if [ $swapon_result -ne 0 ]; then
echo -e "${YELLOW}swapon 单个文件失败,尝试 swapon -a${NC}"
swapon -a 2>/dev/null
swapon_result=$?
fi
if [ $swapon_result -eq 0 ]; then
echo -e "${GREEN}✓ 虚拟内存已成功开启${NC}"
log_info "swap启用成功"
# 询问是否添加到fstab
if ! grep -q "$SWAP_FILE" /etc/fstab 2>/dev/null; then
echo ""
read -p "是否添加到 /etc/fstab 以便开机自动启用?(y/n): " confirm
confirm=$(echo "$confirm" | tr '[:upper:]' '[:lower:]')
if [ "$confirm" = "y" ]; then
backup_fstab
echo "$SWAP_FILE none swap sw 0 0" >> /etc/fstab
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ 已添加到 /etc/fstab${NC}"
log_info "已添加到fstab"
else
echo -e "${RED}✗ 添加到fstab失败${NC}"
log_error "添加到fstab失败"
fi
fi
else
echo -e "${GREEN}✓ Swap文件已在fstab中配置${NC}"
fi
else
echo -e "${RED}✗ 开启虚拟内存失败${NC}"
log_error "swap启用失败"
return 1
fi
echo ""
show_status
return 0
}
# -----------------------------------------------------------------------------
# 删除swap文件
# -----------------------------------------------------------------------------
swap_delete() {
echo -e "${YELLOW}正在删除swap文件...${NC}"
echo ""
log_info "开始删除swap"
if [ ! -f "$SWAP_FILE" ]; then
echo -e "${RED}错误: $SWAP_FILE 不存在${NC}"
log_error "swap文件不存在"
return 1
fi
# 检查swap使用率
local swap_total=$(free | awk '/Swap/ {print $2}')
local swap_used=$(free | awk '/Swap/ {print $3}')
if [ "$swap_total" -gt 0 ] 2>/dev/null && [ "$swap_used" -gt 0 ] 2>/dev/null; then
local swap_percent=$((swap_used * 100 / swap_total))
echo -e "${YELLOW}当前swap使用率: ${swap_percent}%${NC}"
if [ "$swap_percent" -gt 80 ]; then
echo -e "${RED}警告: swap使用率过高${NC}"
echo -e "${CYAN}尝试清理页面缓存...${NC}"
sync
echo 3 > /proc/sys/vm/drop_caches 2>/dev/null
sleep 2
fi
echo ""
read -p "是否继续?(y/n): " confirm
confirm=$(echo "$confirm" | tr '[:upper:]' '[:lower:]')
if [ "$confirm" != "y" ]; then
echo "操作已取消"
log_info "用户取消删除swap"
return 0
fi
fi
# 关闭所有swap
echo -e "${CYAN}正在关闭所有swap...${NC}"
swapoff -a 2>/dev/null
# 等待swap完全关闭
if ! wait_for_swapoff "$SWAP_FILE"; then
echo -e "${RED}✗ 无法关闭swap,文件仍在使用中${NC}"
echo -e "${CYAN}请检查是否有进程正在使用swap${NC}"
log_error "无法关闭swap"
return 1
fi
echo -e "${GREEN}✓ Swap已关闭${NC}"
# 备份并清理fstab配置
echo -e "${CYAN}正在清理fstab配置...${NC}"
if [ -f /etc/fstab ]; then
backup_fstab
# 只删除特定swapfile配置(修复:不过度删除)
local original_count=$(grep -c "$SWAP_FILE" /etc/fstab 2>/dev/null || echo 0)
sed -i "\|^$SWAP_FILE|d" /etc/fstab 2>/dev/null
local new_count=$(grep -c "$SWAP_FILE" /etc/fstab 2>/dev/null || echo 0)
local removed=$((original_count - new_count))
if [ "$removed" -gt 0 ]; then
echo -e "${GREEN}✓ 已删除 $removed 条swapfile配置${NC}"
log_info "从fstab删除 $removed 条配置"
else
echo -e "${YELLOW}fstab中无swapfile配置${NC}"
fi
fi
# 移除文件特殊属性
echo -e "${CYAN}正在移除文件特殊属性...${NC}"
chattr -i "$SWAP_FILE" 2>/dev/null
chattr -a "$SWAP_FILE" 2>/dev/null
log_info "已移除文件特殊属性"
# 删除文件
echo -e "${CYAN}正在删除swap文件...${NC}"
rm -f "$SWAP_FILE"
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ Swap文件已删除${NC}"
log_info "swap文件删除成功"
else
echo -e "${RED}✗ 删除失败${NC}"
echo -e "${CYAN}诊断信息:${NC}"
ls -la "$SWAP_FILE" 2>/dev/null
lsattr "$SWAP_FILE" 2>/dev/null
log_error "swap文件删除失败"
return 1
fi
# 验证删除
if [ -f "$SWAP_FILE" ]; then
echo -e "${RED}✗ 验证失败: 文件仍然存在${NC}"
log_error "删除验证失败"
return 1
fi
echo ""
echo -e "${GREEN}╔════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ 删除完成 ║${NC}"
echo -e "${GREEN}╚════════════════════════════════════════╝${NC}"
echo ""
show_status
return 0
}
# -----------------------------------------------------------------------------
# 设置swappiness
# -----------------------------------------------------------------------------
set_swappiness() {
local value="$1"
# 默认值
if [ -z "$value" ]; then
value=60
fi
# 验证值范围
if ! [[ "$value" =~ ^[0-9]+$ ]]; then
echo -e "${RED}错误: swappiness值必须是数字${NC}"
log_error "无效的swappiness值: $value"
return 1
fi
if [ "$value" -lt 0 ] || [ "$value" -gt 100 ]; then
echo -e "${RED}错误: swappiness值必须在 0-100 之间${NC}"
log_error "swappiness值超出范围: $value"
return 1
fi
log_info "设置swappiness: $value"
# 临时设置
echo "$value" > /proc/sys/vm/swappiness 2>/dev/null
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ swappiness 已临时设置为 $value${NC}"
log_info "swappiness临时设置成功"
else
echo -e "${RED}✗ 设置失败${NC}"
log_error "swappiness设置失败"
return 1
fi
# 询问是否永久保存
echo ""
read -p "是否永久保存此设置?(y/n): " confirm
confirm=$(echo "$confirm" | tr '[:upper:]' '[:lower:]')
if [ "$confirm" = "y" ]; then
# 确保目录存在
mkdir -p /etc/sysctl.d 2>/dev/null
local sysctl_file="/etc/sysctl.d/99-swappiness.conf"
echo "vm.swappiness=$value" > "$sysctl_file" 2>/dev/null
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ 已保存到 $sysctl_file${NC}"
log_info "swappiness永久配置保存到: $sysctl_file"
# 验证配置
sysctl -p "$sysctl_file" 2>/dev/null
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ 配置验证通过${NC}"
fi
else
echo -e "${RED}✗ 保存配置失败${NC}"
log_error "保存swappiness配置失败"
fi
fi
echo ""
echo -e "${CYAN}Swappiness值说明:${NC}"
echo " 0 = 尽量避免使用swap (适合SSD/大内存)"
echo " 10 = 适合桌面环境"
echo " 60 = 默认值"
echo " 100 = 积极使用swap (适合小内存)"
return 0
}
# -----------------------------------------------------------------------------
# 显示帮助信息
# -----------------------------------------------------------------------------
show_help() {
echo -e "${GREEN}╔════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ Swap 管理脚本 v4.0.0 (生产级) ║${NC}"
echo -e "${GREEN}╚════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "${CYAN}用法:${NC} sudo $SCRIPT_NAME [命令] [参数]"
echo ""
echo -e "${CYAN}命令:${NC}"
echo " on [大小] 开启虚拟内存 (可指定大小如 2G, 4G, 8G)"
echo " off 关闭虚拟内存"
echo " status 查看当前状态"
echo " delete 删除swap文件(自动清理配置)"
echo " swappiness [值] 设置swap使用倾向 (0-100)"
echo " restore 从备份恢复fstab配置"
echo " help 显示此帮助信息"
echo ""
echo -e "${CYAN}示例:${NC}"
echo " sudo $SCRIPT_NAME status # 查看状态"
echo " sudo $SCRIPT_NAME on 4G # 创建4G swap并开启"
echo " sudo $SCRIPT_NAME off # 关闭swap"
echo " sudo $SCRIPT_NAME delete # 删除swap文件"
echo " sudo $SCRIPT_NAME swappiness 10 # 设置swappiness为10"
echo " sudo $SCRIPT_NAME restore # 恢复fstab备份"
echo ""
echo -e "${CYAN}支持的大小单位:${NC} K, M, G (如 512M, 1G, 4G, 8G, 2GB)"
echo ""
echo -e "${CYAN}日志文件:${NC} $LOG_FILE"
echo -e "${CYAN}备份目录:${NC} $FSTAB_BACKUP_DIR"
echo ""
}
# -----------------------------------------------------------------------------
# 主程序
# -----------------------------------------------------------------------------
main() {
init_check "$@"
case "$1" in
on)
if [ -n "$2" ]; then
validate_size "$2"
swap_on "$2"
else
swap_on
fi
;;
off)
swap_off
;;
status)
show_status
;;
delete)
swap_delete
;;
swappiness)
set_swappiness "$2"
;;
restore)
restore_fstab
;;
help|--help|-h)
show_help
;;
"")
echo -e "${RED}错误: 未指定命令${NC}"
echo ""
show_help
exit 1
;;
*)
echo -e "${RED}错误: 未知命令 '$1'${NC}"
echo ""
show_help
exit 1
;;
esac
log_info "========== 脚本结束 =========="
}
# 执行主程序
main "$@"
评论