482 lines
15 KiB
Bash
482 lines
15 KiB
Bash
#!/usr/bin/env bash
|
||
|
||
# ==============================================================================
|
||
# Linux 全能系统管理工具 (Pro版)
|
||
# 支持: Debian系 / RHEL系(含麒麟,龙蜥,欧拉) / Arch / Alpine / OpenSUSE
|
||
# 功能: Docker管理 | Swap管理 | 工具箱 | 系统源优化
|
||
# 版本: 2.0.0
|
||
# ==============================================================================
|
||
|
||
# ---------- 1. 全局配置与初始化 ----------
|
||
|
||
# 严格模式 (部分开启,避免过早退出)
|
||
set -o pipefail
|
||
|
||
# 路径配置
|
||
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
readonly LOG_FILE="${SCRIPT_DIR}/sys_manager.log"
|
||
readonly SWAP_FILE="/swapfile"
|
||
readonly DOCKER_CONFIG="/etc/docker/daemon.json"
|
||
|
||
# 颜色定义
|
||
readonly C_RED='\033[0;31m'
|
||
readonly C_GREEN='\033[0;32m'
|
||
readonly C_YELLOW='\033[1;33m'
|
||
readonly C_BLUE='\033[0;34m'
|
||
readonly C_CYAN='\033[0;36m'
|
||
readonly C_RESET='\033[0m'
|
||
|
||
# 全局变量 (由 sys_detect 填充)
|
||
G_OS_DISTRO="" # 发行版 ID (ubuntu, centos, alpine, kylin...)
|
||
G_PKG_MANAGER="" # 包管理器 (apt, dnf, yum, apk, pacman...)
|
||
G_SVC_MANAGER="" # 服务管理器 (systemd, openrc, service)
|
||
G_IS_CHINA="" # 是否在中国大陆
|
||
|
||
# ---------- 2. 基础工具函数 ----------
|
||
|
||
log() {
|
||
local level="$1"
|
||
local msg="$2"
|
||
local color=""
|
||
case "$level" in
|
||
INFO) color="$C_BLUE" ;;
|
||
SUCCESS) color="$C_GREEN" ;;
|
||
WARN) color="$C_YELLOW" ;;
|
||
ERROR) color="$C_RED" ;;
|
||
esac
|
||
echo -e "${color}[$(date +'%H:%M:%S')][${level}]${C_RESET} ${msg}" | tee -a "$LOG_FILE"
|
||
}
|
||
|
||
# 装饰性标题
|
||
print_banner() {
|
||
local title="$1"
|
||
echo
|
||
echo -e "${C_CYAN}══════════════════════════════════════════════════════${C_RESET}"
|
||
echo -e "${C_CYAN} $title${C_RESET}"
|
||
echo -e "${C_CYAN}══════════════════════════════════════════════════════${C_RESET}"
|
||
echo
|
||
}
|
||
|
||
# 交互确认
|
||
confirm() {
|
||
local prompt="${1:-确认执行此操作?}"
|
||
local default="${2:-n}" # 默认 no
|
||
local choice
|
||
echo -ne "${C_YELLOW}${prompt} [y/N]: ${C_RESET}"
|
||
read -r choice
|
||
[[ "$choice" =~ ^[Yy]$ ]]
|
||
}
|
||
|
||
pause() {
|
||
echo
|
||
read -rp "按回车键继续..." -s
|
||
echo
|
||
}
|
||
|
||
# ---------- 3. 系统抽象层 (核心) ----------
|
||
|
||
sys_detect() {
|
||
# 1. 权限检查
|
||
[[ $EUID -ne 0 ]] && { log ERROR "请使用 sudo 或 root 运行此脚本"; exit 1; }
|
||
|
||
# 2. 发行版检测
|
||
if [[ -f /etc/os-release ]]; then
|
||
source /etc/os-release
|
||
G_OS_DISTRO="${ID,,}"
|
||
else
|
||
G_OS_DISTRO="unknown"
|
||
fi
|
||
|
||
# 3. 包管理器检测
|
||
if command -v dnf &>/dev/null; then G_PKG_MANAGER="dnf"
|
||
elif command -v apt &>/dev/null; then G_PKG_MANAGER="apt"
|
||
elif command -v yum &>/dev/null; then G_PKG_MANAGER="yum"
|
||
elif command -v apk &>/dev/null; then G_PKG_MANAGER="apk"
|
||
elif command -v pacman &>/dev/null; then G_PKG_MANAGER="pacman"
|
||
elif command -v zypper &>/dev/null; then G_PKG_MANAGER="zypper"
|
||
else
|
||
log ERROR "无法识别包管理器,不支持此系统"
|
||
exit 1
|
||
fi
|
||
|
||
# 4. 服务管理器检测
|
||
if command -v systemctl &>/dev/null; then G_SVC_MANAGER="systemd"
|
||
elif command -v rc-service &>/dev/null; then G_SVC_MANAGER="openrc" # Alpine
|
||
else G_SVC_MANAGER="service"; fi
|
||
|
||
# 5. 区域检测 (用于镜像源优化)
|
||
if curl -s --connect-timeout 2 -m 2 https://www.google.com &>/dev/null; then
|
||
G_IS_CHINA="false"
|
||
else
|
||
G_IS_CHINA="true"
|
||
fi
|
||
}
|
||
|
||
# 统一包安装接口
|
||
sys_install_pkg() {
|
||
local pkgs=("$@")
|
||
[[ ${#pkgs[@]} -eq 0 ]] && return 0
|
||
|
||
log INFO "正在安装: ${pkgs[*]} (使用 $G_PKG_MANAGER)..."
|
||
case "$G_PKG_MANAGER" in
|
||
apt) apt-get update -qq && apt-get install -y "${pkgs[@]}" ;;
|
||
dnf|yum) $G_PKG_MANAGER install -y "${pkgs[@]}" ;;
|
||
apk) apk add --no-cache "${pkgs[@]}" ;;
|
||
pacman) pacman -Sy --noconfirm "${pkgs[@]}" ;;
|
||
zypper) zypper install -y --no-confirm "${pkgs[@]}" ;;
|
||
esac
|
||
}
|
||
|
||
# 统一包卸载接口
|
||
sys_remove_pkg() {
|
||
local pkgs=("$@")
|
||
[[ ${#pkgs[@]} -eq 0 ]] && return 0
|
||
|
||
log INFO "正在卸载: ${pkgs[*]}..."
|
||
case "$G_PKG_MANAGER" in
|
||
apt) apt-get purge -y "${pkgs[@]}" && apt-get autoremove -y ;;
|
||
dnf|yum) $G_PKG_MANAGER remove -y "${pkgs[@]}" ;;
|
||
apk) apk del "${pkgs[@]}" ;;
|
||
pacman) pacman -Rs --noconfirm "${pkgs[@]}" ;;
|
||
zypper) zypper remove -y "${pkgs[@]}" ;;
|
||
esac
|
||
}
|
||
|
||
# 统一服务管理接口
|
||
sys_service() {
|
||
local action="$1" # start, stop, restart, enable
|
||
local service="$2"
|
||
|
||
[[ -z "$service" ]] && return 1
|
||
|
||
case "$G_SVC_MANAGER" in
|
||
systemd)
|
||
[[ "$action" == "enable" ]] && systemctl enable --now "$service" || systemctl "$action" "$service"
|
||
;;
|
||
openrc)
|
||
[[ "$action" == "enable" ]] && rc-update add "$service" default && rc-service "$service" start || rc-service "$service" "$action"
|
||
;;
|
||
*)
|
||
service "$service" "$action"
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# ---------- 4. Docker 模块 ----------
|
||
|
||
mod_docker_menu() {
|
||
while true; do
|
||
clear
|
||
print_banner "Docker 容器管理"
|
||
local status="未安装"
|
||
command -v docker &>/dev/null && status="${C_GREEN}已安装 $(docker --version | awk '{print $3}' | tr -d ,)${C_RESET}"
|
||
|
||
echo -e "当前状态: $status"
|
||
echo "1. 安装 Docker (自动适配源)"
|
||
echo "2. 配置国内镜像加速 (智能检测)"
|
||
echo "3. 卸载 Docker"
|
||
echo "0. 返回上级"
|
||
echo
|
||
read -rp "请选择: " opt
|
||
case $opt in
|
||
1) mod_docker_install ;;
|
||
2) mod_docker_mirror ;;
|
||
3) mod_docker_remove ;;
|
||
0) return ;;
|
||
*) log ERROR "无效选择" ;;
|
||
esac
|
||
pause
|
||
done
|
||
}
|
||
|
||
mod_docker_install() {
|
||
if command -v docker &>/dev/null; then
|
||
log WARN "Docker 已安装"
|
||
return
|
||
fi
|
||
|
||
log INFO "开始安装 Docker..."
|
||
|
||
# 特殊处理 Alpine
|
||
if [[ "$G_OS_DISTRO" == "alpine" ]]; then
|
||
sys_install_pkg docker docker-compose
|
||
sys_service enable docker
|
||
log SUCCESS "Docker 安装完成 (Alpine)"
|
||
return
|
||
fi
|
||
|
||
# 通用官方脚本安装 (兼容性最好)
|
||
local install_cmd="curl -fsSL https://get.docker.com | bash"
|
||
if [[ "$G_IS_CHINA" == "true" ]]; then
|
||
install_cmd="curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun"
|
||
fi
|
||
|
||
eval "$install_cmd"
|
||
|
||
if command -v docker &>/dev/null; then
|
||
sys_service enable docker
|
||
log SUCCESS "Docker 安装成功"
|
||
else
|
||
log ERROR "Docker 安装失败,请检查网络或系统日志"
|
||
fi
|
||
}
|
||
|
||
mod_docker_mirror() {
|
||
if ! command -v docker &>/dev/null; then log ERROR "请先安装 Docker"; return; fi
|
||
[[ "$G_IS_CHINA" != "true" ]] && { log INFO "检测到非中国大陆IP,通常无需配置加速"; confirm "仍要配置吗?" || return; }
|
||
|
||
local mirrors='["https://docker.1panel.live", "https://docker.m.daocloud.io"]'
|
||
|
||
mkdir -p "$(dirname "$DOCKER_CONFIG")"
|
||
cat > "$DOCKER_CONFIG" <<EOF
|
||
{
|
||
"registry-mirrors": $mirrors,
|
||
"log-driver": "json-file",
|
||
"log-opts": {"max-size": "50m", "max-file": "3"}
|
||
}
|
||
EOF
|
||
sys_service restart docker
|
||
log SUCCESS "镜像加速配置完成"
|
||
}
|
||
|
||
mod_docker_remove() {
|
||
confirm "确定彻底卸载 Docker 及其数据吗?" || return
|
||
sys_service stop docker
|
||
|
||
# 根据包管理器卸载
|
||
local pkgs=(docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker docker-engine docker.io containerd runc)
|
||
sys_remove_pkg "${pkgs[@]}"
|
||
|
||
rm -rf /var/lib/docker /var/lib/containerd /etc/docker
|
||
log SUCCESS "Docker 已卸载并清理数据"
|
||
}
|
||
|
||
# ---------- 5. Swap 交换分区模块 ----------
|
||
|
||
mod_swap_menu() {
|
||
while true; do
|
||
clear
|
||
print_banner "Swap 虚拟内存管理"
|
||
|
||
# 获取当前 Swap 信息
|
||
local current_swap
|
||
current_swap=$(free -m | awk '/Swap/ {print $2}')
|
||
local swap_status="${C_RED}未启用${C_RESET}"
|
||
[[ "$current_swap" -gt 0 ]] && swap_status="${C_GREEN}已启用 (${current_swap} MB)${C_RESET}"
|
||
|
||
echo -e "当前状态: $swap_status"
|
||
echo "1. 创建/扩容 Swap"
|
||
echo "2. 删除 Swap"
|
||
echo "0. 返回上级"
|
||
echo
|
||
read -rp "请选择: " opt
|
||
case $opt in
|
||
1) mod_swap_create ;;
|
||
2) mod_swap_remove ;;
|
||
0) return ;;
|
||
esac
|
||
pause
|
||
done
|
||
}
|
||
|
||
mod_swap_create() {
|
||
# 检查虚拟化限制
|
||
if [[ -d "/proc/vz" && ! -d "/proc/bc" ]]; then
|
||
log ERROR "OpenVZ 架构通常不支持 Swap"
|
||
return
|
||
fi
|
||
|
||
if grep -q "$SWAP_FILE" /etc/fstab; then
|
||
log WARN "发现已存在的 Swap 配置,请先删除"
|
||
return
|
||
fi
|
||
|
||
local mem_total
|
||
mem_total=$(free -m | awk '/Mem:/ {print $2}')
|
||
local recommend=$((mem_total < 2048 ? mem_total * 2 : mem_total))
|
||
|
||
echo -e "物理内存: ${mem_total} MB"
|
||
read -rp "请输入 Swap 大小 (MB) [默认 ${recommend}]: " size
|
||
size=${size:-$recommend}
|
||
|
||
log INFO "正在创建 ${size} MB 的 Swap 文件..."
|
||
|
||
# 兼容性创建 (dd 比 fallocate 兼容性好,尤其是 btrfs/xfs 某些情况)
|
||
dd if=/dev/zero of="$SWAP_FILE" bs=1M count="$size" status=progress
|
||
|
||
chmod 600 "$SWAP_FILE"
|
||
mkswap "$SWAP_FILE"
|
||
swapon "$SWAP_FILE"
|
||
|
||
# 持久化
|
||
echo "$SWAP_FILE none swap sw 0 0" >> /etc/fstab
|
||
log SUCCESS "Swap 创建成功"
|
||
}
|
||
|
||
mod_swap_remove() {
|
||
confirm "确定删除 Swap 吗?" || return
|
||
swapoff "$SWAP_FILE" 2>/dev/null
|
||
sed -i "\|$SWAP_FILE|d" /etc/fstab
|
||
rm -f "$SWAP_FILE"
|
||
log SUCCESS "Swap 已移除"
|
||
}
|
||
|
||
# ---------- 6. 常用工具模块 ----------
|
||
|
||
# 定义工具字典 (格式: "工具名:apt包名:yum包名:apk包名:pacman包名:zypper包名")
|
||
# 如果包名相同,后续可以省略,脚本会自动回退使用默认名
|
||
# 例如: "vim" 在所有系统都叫 vim,除了 alpine 叫 vim (这里只是举例逻辑)
|
||
declare -A TOOLS_MAP=(
|
||
["vim"]="vim:vim:vim:vim:vim:vim"
|
||
["wget"]="wget"
|
||
["curl"]="curl"
|
||
["git"]="git"
|
||
["htop"]="htop"
|
||
["tmux"]="tmux"
|
||
["zsh"]="zsh"
|
||
["unzip"]="unzip"
|
||
["net-tools"]="net-tools:net-tools:net-tools:net-tools:net-tools:net-tools" # ifconfig
|
||
["ping"]="iputils-ping:iputils:iputils:iputils-ping:iputils:iputils" # ping 命令包名差异大
|
||
)
|
||
|
||
mod_tools_get_pkg_name() {
|
||
local tool=$1
|
||
local def="${TOOLS_MAP[$tool]}"
|
||
local pkg_name=""
|
||
|
||
IFS=':' read -r -a parts <<< "$def"
|
||
|
||
# 根据全局 G_PKG_MANAGER 映射索引
|
||
# 0:通用/apt, 1:yum/dnf, 2:apk, 3:pacman, 4:zypper
|
||
local idx=0
|
||
case "$G_PKG_MANAGER" in
|
||
apt) idx=1 ;;
|
||
yum|dnf) idx=2 ;;
|
||
apk) idx=3 ;;
|
||
pacman) idx=4 ;;
|
||
zypper) idx=5 ;;
|
||
esac
|
||
|
||
# 获取对应位置的包名,如果没有则使用第一位(通用名)
|
||
if [[ -n "${parts[$idx]}" ]]; then
|
||
echo "${parts[$idx]}"
|
||
else
|
||
echo "${parts[0]}" # Fallback
|
||
fi
|
||
}
|
||
|
||
mod_tools_menu() {
|
||
while true; do
|
||
clear
|
||
print_banner "常用工具箱 (适配 $G_PKG_MANAGER)"
|
||
|
||
local i=1
|
||
local tool_list=()
|
||
for tool in "${!TOOLS_MAP[@]}"; do
|
||
local status="${C_RED}未装${C_RESET}"
|
||
# 简单的检查命令是否存在,部分包名和命令名不一致的需特殊处理,这里简化处理
|
||
if command -v "$tool" &>/dev/null || ([[ "$tool" == "ping" ]] && command -v ping &>/dev/null); then
|
||
status="${C_GREEN}已装${C_RESET}"
|
||
fi
|
||
printf "%2d. %-12s [%s]\n" "$i" "$tool" "$status"
|
||
tool_list+=("$tool")
|
||
((i++))
|
||
done
|
||
|
||
echo
|
||
echo " a. 一键安装所有"
|
||
echo " 0. 返回上级"
|
||
echo
|
||
read -rp "请输入序号安装 (支持多选,空格分隔,如 1 3): " choices
|
||
|
||
case "$choices" in
|
||
0) return ;;
|
||
a|A)
|
||
local all_pkgs=()
|
||
for t in "${tool_list[@]}"; do
|
||
all_pkgs+=("$(mod_tools_get_pkg_name "$t")")
|
||
done
|
||
sys_install_pkg "${all_pkgs[@]}"
|
||
pause
|
||
;;
|
||
*)
|
||
local install_list=()
|
||
for c in $choices; do
|
||
if [[ "$c" =~ ^[0-9]+$ ]] && [ "$c" -le "${#tool_list[@]}" ] && [ "$c" -ge 1 ]; then
|
||
local t_name="${tool_list[$((c-1))]}"
|
||
install_list+=("$(mod_tools_get_pkg_name "$t_name")")
|
||
fi
|
||
done
|
||
|
||
if [[ ${#install_list[@]} -gt 0 ]]; then
|
||
sys_install_pkg "${install_list[@]}"
|
||
else
|
||
log ERROR "无效的选择"
|
||
fi
|
||
pause
|
||
;;
|
||
esac
|
||
done
|
||
}
|
||
|
||
# ---------- 7. 系统源更换模块 ----------
|
||
|
||
mod_mirrors_run() {
|
||
print_banner "系统软件源更换"
|
||
log INFO "正在调用 LinuxMirrors 开源脚本..."
|
||
log WARN "此操作将替换系统源配置文件,请确保网络通畅。"
|
||
|
||
if confirm "继续执行?"; then
|
||
# 确保有 curl
|
||
if ! command -v curl &>/dev/null; then
|
||
sys_install_pkg curl
|
||
fi
|
||
|
||
# 调用成熟的外部脚本,避免重复造轮子
|
||
bash <(curl -sSL https://linuxmirrors.cn/main.sh)
|
||
fi
|
||
}
|
||
|
||
# ---------- 8. 主程序循环 ----------
|
||
|
||
main() {
|
||
sys_detect # 系统环境初始化
|
||
|
||
# 捕获 Ctrl+C
|
||
trap 'echo -e "\n${C_YELLOW}用户取消操作,正在退出...${C_RESET}"; exit 0' SIGINT
|
||
|
||
while true; do
|
||
clear
|
||
print_banner "Linux System Manager Pro"
|
||
echo -e " 系统信息: ${C_GREEN}$G_OS_DISTRO${C_RESET} | 包管理: ${C_GREEN}$G_PKG_MANAGER${C_RESET} | 区域: $([[ "$G_IS_CHINA" == "true" ]] && echo "CN" || echo "Global")"
|
||
echo -e " 核心时间: $(uptime -p)"
|
||
echo
|
||
echo " 1. Docker 管理中心 (容器/镜像/加速)"
|
||
echo " 2. Swap 虚拟内存 (创建/扩容/删除)"
|
||
echo " 3. 常用工具箱 (Vim/Git/Tmux...)"
|
||
echo " 4. 系统源一键更换 (调用 LinuxMirrors)"
|
||
echo " 5. 查看系统日志 (查看脚本运行记录)"
|
||
echo " 0. 退出程序"
|
||
echo
|
||
read -rp " 请输入数字 [0-5]: " choice
|
||
|
||
case "$choice" in
|
||
1) mod_docker_menu ;;
|
||
2) mod_swap_menu ;;
|
||
3) mod_tools_menu ;;
|
||
4) mod_mirrors_run ;;
|
||
5)
|
||
echo
|
||
tail -n 20 "$LOG_FILE"
|
||
pause
|
||
;;
|
||
0)
|
||
log INFO "退出程序"
|
||
exit 0
|
||
;;
|
||
*) log ERROR "输入错误" ; sleep 1 ;;
|
||
esac
|
||
done
|
||
}
|
||
|
||
main |