232 lines
5.5 KiB
Bash
232 lines
5.5 KiB
Bash
#!/usr/bin/env bash
|
||
|
||
# Linux 交换文件管理脚本
|
||
# 描述: 在 Linux VPS 上添加或删除交换文件
|
||
|
||
set -euo pipefail # 遇到错误、未定义变量、管道失败时退出
|
||
|
||
# 颜色定义
|
||
readonly RED='\033[0;31m'
|
||
readonly GREEN='\033[0;32m'
|
||
readonly YELLOW='\033[1;33m'
|
||
readonly NC='\033[0m' # 无颜色
|
||
|
||
# 配置项
|
||
readonly SWAPFILE="/swapfile"
|
||
readonly SCRIPT_NAME="$(basename "$0")"
|
||
|
||
# 日志输出函数
|
||
log_info() {
|
||
echo -e "${GREEN}[信息]${NC} $*"
|
||
}
|
||
|
||
log_warn() {
|
||
echo -e "${YELLOW}[警告]${NC} $*"
|
||
}
|
||
|
||
log_error() {
|
||
echo -e "${RED}[错误]${NC} $*" >&2
|
||
}
|
||
|
||
# 检查是否以 root 权限运行
|
||
check_root() {
|
||
if [[ $EUID -ne 0 ]]; then
|
||
log_error "此脚本必须以 root 权限运行!"
|
||
log_info "请使用: sudo $SCRIPT_NAME"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# 检查系统是否支持交换文件(非 OpenVZ)
|
||
check_virtualization() {
|
||
if [[ -d "/proc/vz" ]] && [[ ! -d "/proc/bc" ]]; then
|
||
log_error "OpenVZ 容器不支持交换文件!"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# 验证交换文件大小输入
|
||
validate_swap_size() {
|
||
local size="$1"
|
||
|
||
if ! [[ "$size" =~ ^[0-9]+$ ]] || [[ "$size" -lt 64 ]]; then
|
||
log_error "无效的交换文件大小。必须是数字且 >= 64 MB"
|
||
return 1
|
||
fi
|
||
|
||
# 检查可用磁盘空间
|
||
local available_space
|
||
available_space=$(df / | awk 'NR==2 {print int($4/1024)}')
|
||
|
||
if [[ "$size" -gt "$available_space" ]]; then
|
||
log_error "磁盘空间不足。可用: ${available_space}MB,需要: ${size}MB"
|
||
return 1
|
||
fi
|
||
|
||
return 0
|
||
}
|
||
|
||
# 获取系统内存大小
|
||
get_memory_size() {
|
||
awk '/MemTotal/ {print int($2/1024)}' /proc/meminfo
|
||
}
|
||
|
||
# 检查交换文件是否已存在
|
||
swap_exists() {
|
||
grep -q "$SWAPFILE" /etc/fstab 2>/dev/null
|
||
}
|
||
|
||
# 显示当前交换文件信息
|
||
show_swap_info() {
|
||
log_info "当前交换文件信息:"
|
||
if [[ -f /proc/swaps ]]; then
|
||
cat /proc/swaps
|
||
fi
|
||
echo
|
||
grep "Swap" /proc/meminfo || true
|
||
}
|
||
|
||
# 添加交换文件
|
||
add_swap() {
|
||
if swap_exists; then
|
||
log_error "交换文件已存在!"
|
||
log_info "请先使用选项 2 删除现有的交换文件"
|
||
return 1
|
||
fi
|
||
|
||
local memory_mb
|
||
memory_mb=$(get_memory_size)
|
||
local suggested_size=$((memory_mb * 2))
|
||
|
||
echo
|
||
log_info "当前系统内存: ${memory_mb}MB"
|
||
log_info "建议交换文件大小: ${suggested_size}MB (内存的2倍)"
|
||
echo
|
||
|
||
read -rp "请输入交换文件大小(MB),直接回车使用建议值 ${suggested_size}MB: " swap_size
|
||
swap_size=${swap_size:-$suggested_size}
|
||
|
||
if ! validate_swap_size "$swap_size"; then
|
||
return 1
|
||
fi
|
||
|
||
log_info "正在创建 ${swap_size}MB 交换文件..."
|
||
|
||
# 使用更高效的方式创建交换文件
|
||
if command -v fallocate >/dev/null 2>&1; then
|
||
fallocate -l "${swap_size}M" "$SWAPFILE"
|
||
else
|
||
dd if=/dev/zero of="$SWAPFILE" bs=1M count="$swap_size" status=progress
|
||
fi
|
||
|
||
# 设置正确的权限
|
||
chmod 600 "$SWAPFILE"
|
||
|
||
# 设置交换文件
|
||
mkswap "$SWAPFILE"
|
||
swapon "$SWAPFILE"
|
||
|
||
# 添加到 fstab 以实现持久化
|
||
echo "$SWAPFILE none swap sw 0 0" >> /etc/fstab
|
||
|
||
log_info "交换文件创建成功!"
|
||
echo
|
||
show_swap_info
|
||
}
|
||
|
||
# 删除交换文件
|
||
remove_swap() {
|
||
if ! swap_exists; then
|
||
log_warn "未找到需要删除的交换文件"
|
||
return 0
|
||
fi
|
||
|
||
log_info "正在删除交换文件..."
|
||
|
||
# 关闭交换
|
||
if swapon --show | grep -q "$SWAPFILE"; then
|
||
swapoff "$SWAPFILE"
|
||
fi
|
||
|
||
# 从 fstab 中移除
|
||
if grep -q "$SWAPFILE" /etc/fstab; then
|
||
sed -i "\|$SWAPFILE|d" /etc/fstab
|
||
fi
|
||
|
||
# 删除交换文件
|
||
if [[ -f "$SWAPFILE" ]]; then
|
||
rm -f "$SWAPFILE"
|
||
fi
|
||
|
||
# 清理缓存
|
||
sync
|
||
echo 3 > /proc/sys/vm/drop_caches 2>/dev/null || true
|
||
|
||
log_info "交换文件删除成功!"
|
||
echo
|
||
show_swap_info
|
||
}
|
||
|
||
# 显示菜单
|
||
show_menu() {
|
||
clear
|
||
cat << 'EOF'
|
||
╔══════════════════════════════════════╗
|
||
║ Linux 交换文件管理 ║
|
||
╠══════════════════════════════════════╣
|
||
║ 1. 添加交换文件 ║
|
||
║ 2. 删除交换文件 ║
|
||
║ 3. 显示交换文件信息 ║
|
||
║ 4. 退出程序 ║
|
||
╚══════════════════════════════════════╝
|
||
EOF
|
||
echo
|
||
}
|
||
|
||
# 主菜单循环
|
||
main_menu() {
|
||
while true; do
|
||
show_menu
|
||
read -rp "请选择操作 [1-4]: " choice
|
||
echo
|
||
|
||
case "$choice" in
|
||
1)
|
||
add_swap
|
||
;;
|
||
2)
|
||
remove_swap
|
||
;;
|
||
3)
|
||
show_swap_info
|
||
;;
|
||
4)
|
||
log_info "再见!"
|
||
exit 0
|
||
;;
|
||
*)
|
||
log_error "无效选择。请输入 1-4"
|
||
sleep 2
|
||
continue
|
||
;;
|
||
esac
|
||
|
||
echo
|
||
read -rp "按回车键继续..."
|
||
done
|
||
}
|
||
|
||
# 主函数
|
||
main() {
|
||
# 执行系统检查
|
||
check_root
|
||
check_virtualization
|
||
|
||
# 启动主菜单
|
||
main_menu
|
||
}
|
||
|
||
# 脚本入口点
|
||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||
main "$@"
|
||
fi |