commit edf912c01ee3535f4a0b1e6d9563c3c241bb19b7 Author: fanhuadesenlinnn Date: Sun Sep 14 17:34:24 2025 +0800 上传文件至 / diff --git a/banwagong.sh b/banwagong.sh new file mode 100644 index 0000000..339bcf7 --- /dev/null +++ b/banwagong.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +SERVER_FILE="servers.txt" + +function list_servers() { + if [[ ! -f $SERVER_FILE ]]; then + echo "暂无服务器,请先添加。" + return + fi + i=0 + while IFS=, read -r name veid api_key; do + ((i++)) + url="https://api.64clouds.com/v1/getLiveServiceInfo?veid=$veid&api_key=$api_key" + resp=$(curl -s "$url") + total=$(echo "$resp" | jq '.plan_monthly_data // 0') + used=$(echo "$resp" | jq '.data_counter // 0') + ip=$(echo "$resp" | jq -r '.ip_addresses // "未知"') + reset=$(echo "$resp" | jq '.data_next_reset // empty') + if [[ -n $reset ]]; then + reset_date=$(date -r "$reset" "+%Y-%m-%d %H:%M") + else + reset_date="未知" + fi + total_gb=$(awk "BEGIN{printf \"%.2f\", $total/1024/1024/1024}") + remain_gb=$(awk "BEGIN{printf \"%.2f\", ($total-$used)/1024/1024/1024}") + echo "$i. $name" + echo " IP: $ip" + echo " 总流量: $total_gb GB" + echo " 剩余流量: $remain_gb GB" + echo " 重置日期: $reset_date" + echo "-----------------------------" + done < "$SERVER_FILE" +} + +function add_server() { + read -p "服务器名称: " name + read -p "VEID: " veid + read -p "API Key: " api_key + echo "$name,$veid,$api_key" >> "$SERVER_FILE" + echo "添加成功。" +} + +function delete_server() { + list_servers + read -p "输入要删除的序号: " idx + sed -i '' "${idx}d" "$SERVER_FILE" + echo "已删除。" +} + +function edit_server() { + list_servers + read -p "输入要编辑的序号: " idx + sed -n "${idx}p" "$SERVER_FILE" + read -p "新服务器名称: " name + read -p "新VEID: " veid + read -p "新API Key: " api_key + sed -i '' "${idx}s/.*/$name,$veid,$api_key/" "$SERVER_FILE" + echo "已更新。" +} + +function menu() { + echo "1. 查看服务器流量" + echo "2. 添加服务器" + echo "3. 删除服务器" + echo "4. 编辑服务器" + echo "0. 退出" + read -p "选择操作: " op + case $op in + 1) list_servers ;; + 2) add_server ;; + 3) delete_server ;; + 4) edit_server ;; + 0) exit 0 ;; + *) echo "无效选项" ;; + esac +} + +while true; do + menu +done \ No newline at end of file diff --git a/docker.sh b/docker.sh new file mode 100644 index 0000000..6e6609c --- /dev/null +++ b/docker.sh @@ -0,0 +1,273 @@ +#!/bin/env bash + +# Docker 安装脚本 +# 支持中国大陆和海外环境 + +set -euo pipefail + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly LOG_FILE="${SCRIPT_DIR}/docker_install.log" +readonly DAEMON_JSON="/etc/docker/daemon.json" +readonly BACKUP_FILE="${DAEMON_JSON}.backup" + +# 颜色定义 +readonly RED='\033[0;31m' +readonly GREEN='\033[0;32m' +readonly YELLOW='\033[1;33m' +readonly BLUE='\033[0;34m' +readonly NC='\033[0m' # No Color + +# 日志函数 +log() { + echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE" +} + +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" | tee -a "$LOG_FILE" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" | tee -a "$LOG_FILE" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" | tee -a "$LOG_FILE" +} + +# 检测地区 +detect_region() { + local country + country=$(curl -s --connect-timeout 5 --max-time 10 ipinfo.io/country 2>/dev/null || echo "") + [[ "$country" == "CN" ]] +} + +# 检查Docker版本 +check_docker_version() { + if ! command -v docker &>/dev/null; then + return 1 + fi + + local version + version=$(docker --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+' | head -n1) + local major="${version%%.*}" + + if [[ ${major:-0} -lt 20 ]]; then + log_warn "Docker版本过低 (${version}),建议升级到20.x或更高版本" + else + log_info "检测到Docker版本: ${version}" + fi + + return 0 +} + +# 创建daemon.json配置 +create_daemon_json() { + local accelerator_url="${1:-}" + + if [[ -n "$accelerator_url" ]]; then + log_info "配置Docker镜像加速器: $accelerator_url" + cat > "$DAEMON_JSON" << EOF +{ + "registry-mirrors": ["$accelerator_url"], + "log-driver": "json-file", + "log-opts": { + "max-size": "100m", + "max-file": "3" + }, + "storage-driver": "overlay2" +} +EOF + else + cat > "$DAEMON_JSON" << EOF +{ + "log-driver": "json-file", + "log-opts": { + "max-size": "100m", + "max-file": "3" + }, + "storage-driver": "overlay2" +} +EOF + fi +} + +# 配置加速器 +configure_accelerator() { + if ! detect_region; then + log_info "非中国大陆地区,跳过镜像加速器配置" + return 0 + fi + + echo -n "是否配置Docker镜像加速器?(y/N): " + read -r choice + + case "$choice" in + [yY]|[yY][eE][sS]) + local accelerator_url="" + + # 测试腾讯云镜像可用性 + if ping -c 1 -W 3 mirror.ccs.tencentyun.com &>/dev/null; then + accelerator_url="https://mirror.ccs.tencentyun.com" + else + # 备选阿里云镜像 + accelerator_url="https://registry.cn-hangzhou.aliyuncs.com" + fi + + # 备份现有配置 + [[ -f "$DAEMON_JSON" ]] && cp "$DAEMON_JSON" "$BACKUP_FILE" + + # 创建配置目录 + mkdir -p "$(dirname "$DAEMON_JSON")" + + # 创建新配置 + create_daemon_json "$accelerator_url" + + # 重启Docker服务 + log_info "重启Docker服务..." + systemctl daemon-reload + systemctl restart docker + + log "Docker镜像加速器配置完成" + ;; + *) + log_info "跳过镜像加速器配置" + ;; + esac +} + +# 获取最快的Docker安装源 +get_fastest_source() { + local sources=( + "https://mirrors.aliyun.com/docker-ce" + "https://mirrors.tencent.com/docker-ce" + "https://mirrors.163.com/docker-ce" + ) + + local fastest_source="${sources[0]}" + local min_time=99999 + + for source in "${sources[@]}"; do + local response_time + response_time=$(curl -o /dev/null -s -w '%{time_total}\n' -m 3 "$source" 2>/dev/null || echo "99999") + + if (( $(echo "$response_time < $min_time" | bc -l 2>/dev/null || echo 0) )); then + min_time=$response_time + fastest_source=$source + fi + done + + echo "$fastest_source" +} + +# 下载Docker安装脚本 +download_docker_script() { + local scripts=( + "https://get.docker.com" + "https://cdn.jsdelivr.net/gh/docker/docker-install@master/install.sh" + "https://fastly.jsdelivr.net/gh/docker/docker-install@master/install.sh" + ) + + for script_url in "${scripts[@]}"; do + log_info "尝试从 $script_url 下载安装脚本..." + + if curl -fsSL --connect-timeout 10 --max-time 30 "$script_url" -o get-docker.sh; then + log "下载成功: $script_url" + return 0 + else + log_warn "下载失败: $script_url" + fi + done + + log_error "所有下载尝试均失败" + return 1 +} + +# 安装Docker +install_docker() { + log_info "开始安装Docker..." + + if detect_region; then + log_info "检测到中国大陆地区,使用国内镜像源" + local fastest_source + fastest_source=$(get_fastest_source) + export DOWNLOAD_URL="$fastest_source" + log_info "选择最快源: $fastest_source" + else + log_info "使用官方源" + export DOWNLOAD_URL="https://download.docker.com" + fi + + # 下载安装脚本 + if ! download_docker_script; then + log_error "无法下载Docker安装脚本" + return 1 + fi + + # 执行安装 + log_info "执行Docker安装..." + if sh get-docker.sh 2>&1 | tee -a "$LOG_FILE"; then + log "Docker安装成功" + else + log_error "Docker安装失败" + return 1 + fi + + # 清理安装脚本 + rm -f get-docker.sh + + # 启动并启用Docker服务 + log_info "启动Docker服务..." + systemctl enable docker + systemctl start docker + + # 验证安装 + if docker --version &>/dev/null; then + log "Docker安装验证成功" + docker --version | tee -a "$LOG_FILE" + return 0 + else + log_error "Docker安装验证失败" + return 1 + fi +} + +# 主函数 +main() { + log "开始Docker安装检查..." + + # 检查是否已安装Docker + if check_docker_version; then + log_info "Docker已安装" + configure_accelerator + return 0 + fi + + # 确认安装 + echo -n "Docker未安装,是否现在安装?(y/N): " + read -r install_choice + + case "$install_choice" in + [yY]|[yY][eE][sS]) + if install_docker; then + configure_accelerator + log "Docker安装和配置完成!" + else + log_error "Docker安装失败,请检查日志: $LOG_FILE" + exit 1 + fi + ;; + *) + log_info "取消安装" + exit 0 + ;; + esac +} + +# 检查root权限 +if [[ $EUID -ne 0 ]]; then + log_error "此脚本需要root权限运行" + exit 1 +fi + +# 执行主函数 +main "$@" diff --git a/swap.sh b/swap.sh new file mode 100644 index 0000000..45118d5 --- /dev/null +++ b/swap.sh @@ -0,0 +1,232 @@ +#!/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 \ No newline at end of file diff --git a/system_manager.sh b/system_manager.sh new file mode 100644 index 0000000..61d89c7 --- /dev/null +++ b/system_manager.sh @@ -0,0 +1,1223 @@ +#!/usr/bin/env bash + +# Linux 系统管理工具 +# 功能: Docker安装管理 + 交换文件管理 + 常用工具管理 +# 版本: 1.0.2 + + +# ========== 全局配置 ========== +readonly SCRIPT_NAME="$(basename "$0")" +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly LOG_FILE="${SCRIPT_DIR}/system_manager.log" +readonly SWAPFILE="/swapfile" +readonly DAEMON_JSON="/etc/docker/daemon.json" +readonly TMUX_CONFIG="$HOME/.tmux.conf" +readonly VIM_CONFIG="$HOME/.vimrc" + +# 颜色定义 +readonly RED='\033[0;31m' +readonly GREEN='\033[0;32m' +readonly YELLOW='\033[1;33m' +readonly BLUE='\033[0;34m' +readonly CYAN='\033[0;36m' +readonly NC='\033[0m' + +# ========== 核心工具函数 ========== +log() { + echo -e "${GREEN}[$(date +'%H:%M:%S')]${NC} $*" | tee -a "$LOG_FILE" +} + +log_info() { + echo -e "${BLUE}[信息]${NC} $*" | tee -a "$LOG_FILE" +} + +log_warn() { + echo -e "${YELLOW}[警告]${NC} $*" | tee -a "$LOG_FILE" +} + +log_error() { + echo -e "${RED}[错误]${NC} $*" | tee -a "$LOG_FILE" >&2 +} + +log_success() { + echo -e "${GREEN}[成功]${NC} $*" | tee -a "$LOG_FILE" +} + +# 系统检查 +check_root() { + if [[ $EUID -ne 0 ]]; then + log_error "需要root权限运行此脚本" + log_info "请使用: sudo $SCRIPT_NAME" + exit 1 + fi +} + +check_virtualization() { + if [[ -d "/proc/vz" && ! -d "/proc/bc" ]]; then + log_error "OpenVZ容器不支持此功能" + return 1 + fi + return 0 +} + +detect_region() { + local country + country=$(curl -s --connect-timeout 3 --max-time 5 ipinfo.io/country 2>/dev/null || echo "") + [[ "$country" == "CN" ]] +} + +# 包管理器检测 +detect_package_manager() { + if command -v apt &>/dev/null; then + echo "apt" + elif command -v yum &>/dev/null; then + echo "yum" + elif command -v dnf &>/dev/null; then + echo "dnf" + elif command -v pacman &>/dev/null; then + echo "pacman" + elif command -v zypper &>/dev/null; then + echo "zypper" + else + echo "unknown" + fi +} + +# 发行版检测 +detect_distro() { + if [[ -f /etc/os-release ]]; then + . /etc/os-release + echo "${ID,,}" + elif [[ -f /etc/redhat-release ]]; then + echo "rhel" + elif [[ -f /etc/debian_version ]]; then + echo "debian" + else + echo "unknown" + fi +} + +# 用户交互 +confirm() { + local prompt="${1:-确认操作}" + local default="${2:-N}" + + echo -n "$prompt [y/N]: " + read -r choice + case "${choice:-$default}" in + [yY]|[yY][eE][sS]) return 0 ;; + *) return 1 ;; + esac +} + +pause() { + echo + read -rp "按回车键继续..." -s + echo +} + +# ========== Docker 管理模块 ========== +docker_check_installed() { + command -v docker &>/dev/null +} + +docker_get_version() { + docker --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+' | head -n1 +} + +docker_create_daemon_config() { + local mirror_url="${1:-}" + + mkdir -p "$(dirname "$DAEMON_JSON")" + [[ -f "$DAEMON_JSON" ]] && cp "$DAEMON_JSON" "${DAEMON_JSON}.bak.$(date +%Y%m%d-%H%M-%S)" + + if [[ -n "$mirror_url" ]]; then + cat > "$DAEMON_JSON" << EOF +{ + "registry-mirrors": ["$mirror_url"], + "log-driver": "json-file", + "log-opts": { + "max-size": "100m", + "max-file": "3" + }, + "storage-driver": "overlay2", + "exec-opts": ["native.cgroupdriver=systemd"] +} +EOF + else + cat > "$DAEMON_JSON" << EOF +{ + "log-driver": "json-file", + "log-opts": { + "max-size": "100m", + "max-file": "3" + }, + "storage-driver": "overlay2", + "exec-opts": ["native.cgroupdriver=systemd"] +} +EOF + fi +} + +docker_configure_mirror() { + if ! detect_region; then + log_info "非中国大陆地区,无需配置镜像加速" + return 0 + fi + + if ! confirm "是否配置Docker镜像加速器"; then + return 0 + fi + + local mirrors=( + "https://docker.1panel.live" + "https://mirror.ccs.tencentyun.com" + "https://registry.cn-hangzhou.aliyuncs.com" + "https://dockerhub.azk8s.cn" + ) + + local mirror_url="" + for mirror in "${mirrors[@]}"; do + if curl "${mirror}/v2/" &>/dev/null; then + mirror_url="$mirror" + break + fi + done + + [[ -f "$DAEMON_JSON" ]] && cp "$DAEMON_JSON" "${DAEMON_JSON}.bak.$(date +%Y%m%d-%H%M-%S)" + + docker_create_daemon_config "$mirror_url" + echo $mirror_url + + systemctl daemon-reload + systemctl restart docker + + log_success "Docker镜像加速器配置完成: $mirror_url" +} + +docker_download_script() { + local urls=( + "https://get.docker.com" + "https://cdn.jsdelivr.net/gh/docker/docker-install@master/install.sh" + "https://testingcf.jsdelivr.net/gh/docker/docker-install@master/install.sh" + "https://fastly.jsdelivr.net/gh/docker/docker-install@master/install.sh" + "https://gcore.jsdelivr.net/gh/docker/docker-install@master/install.sh" + "https://raw.githubusercontent.com/docker/docker-install/master/install.sh" + ) + + for url in "${urls[@]}"; do + log_info "尝试下载: $url" + if curl -fsSL --connect-timeout 10 --max-time 30 "$url" -o get-docker.sh; then + log_success "下载成功" + return 0 + fi + log_warn "下载失败: $url" + done + + return 1 +} + +docker_install() { + log_info "开始安装Docker..." + + if detect_region; then + export DOWNLOAD_URL="https://mirrors.aliyun.com/docker-ce" + log_info "使用国内镜像源" + fi + + if ! docker_download_script; then + log_error "无法下载Docker安装脚本" + return 1 + fi + + bash get-docker.sh 2>&1 | tee -a "$LOG_FILE" + rm -f get-docker.sh + + systemctl enable --now docker + + docker --version | tee -a "$LOG_FILE" + log_success "Docker安装完成" +} + +docker_uninstall() { + if ! confirm "确认卸载Docker及所有数据"; then + return 0 + fi + + log_info "停止Docker服务..." + systemctl stop docker.socket docker.service containerd.service 2>/dev/null || true + systemctl stop docker 2>/dev/null || true + + log_info "卸载Docker软件包..." + if command -v apt &>/dev/null; then + apt purge -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + apt autoremove -y + elif command -v yum &>/dev/null; then + yum remove -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + elif command -v dnf &>/dev/null; then + dnf remove -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + fi + + log_info "清理Docker数据..." + rm -rf /var/lib/docker /var/lib/containerd /etc/docker + + log_success "Docker卸载完成" +} + +docker_menu() { + while true; do + clear + cat << 'EOF' +╔══════════════════════════════════════╗ +║ Docker 管理 ║ +╚══════════════════════════════════════╝ +EOF + + if docker_check_installed; then + local version + version=$(docker_get_version) + echo -e "${GREEN}状态: 已安装 (v${version})${NC}" + cat << 'EOF' + +1. 配置镜像加速器 +2. 重启Docker服务 +3. 卸载Docker +0. 返回主菜单 +EOF + else + echo -e "${RED}状态: 未安装${NC}" + cat << 'EOF' + +1. 安装Docker +0. 返回主菜单 +EOF + fi + + echo + read -rp "请选择操作: " choice + + case "$choice" in + 1) + if docker_check_installed; then + docker_configure_mirror + else + docker_install && docker_configure_mirror + fi + pause + ;; + 2) + if docker_check_installed; then + systemctl restart docker && log_success "Docker服务重启完成" + pause + else + continue + fi + ;; + 3) + if docker_check_installed; then + docker_uninstall + pause + else + continue + fi + ;; + 0) + return 0 + ;; + *) + log_error "无效选择" + sleep 1 + ;; + esac + done +} + +# ========== 交换文件管理模块 ========== +swap_exists() { + [[ -f "$SWAPFILE" ]] && grep -q "$SWAPFILE" /etc/fstab 2>/dev/null +} + +swap_get_info() { + if [[ -f "$SWAPFILE" ]]; then + local size_kb + size_kb=$(stat -c%s "$SWAPFILE" 2>/dev/null) + if [[ -n "$size_kb" && "$size_kb" -gt 0 ]]; then + printf "%.0fMB" $((size_kb / 1024 / 1024)) + else + echo "未知大小" + fi + elif swapon --show 2>/dev/null | grep -q "$SWAPFILE"; then + # 如果文件不存在但swap仍激活,从swap信息获取 + awk -v swapfile="$SWAPFILE" '$1 == swapfile {printf "%.0fMB", $3/1024}' /proc/swaps + else + echo "0MB" + fi +} + +swap_validate_size() { + local size="$1" + + if ! [[ "$size" =~ ^[0-9]+$ ]] || [[ "$size" -lt 64 ]]; then + log_error "大小必须是数字且 >= 64MB" + return 1 + fi + + local available + available=$(df / | awk 'NR==2 {print int($4/1024)}') + + if [[ "$size" -gt "$available" ]]; then + log_error "磁盘空间不足 (可用: ${available}MB)" + return 1 + fi + + return 0 +} + +swap_create() { + if swap_exists; then + log_error "交换文件已存在,请先删除" + return 1 + fi + + local memory_mb + memory_mb=$(awk '/MemTotal/ {print int($2/1024)}' /proc/meminfo) + local suggested_size=$((memory_mb < 2048 ? memory_mb * 2 : memory_mb)) + + echo + log_info "系统内存: ${memory_mb}MB" + log_info "建议大小: ${suggested_size}MB" + echo + read -rp "请输入交换文件大小(MB) [${suggested_size}]: " swap_size + swap_size=${swap_size:-$suggested_size} + + if ! swap_validate_size "$swap_size"; then + return 1 + fi + + log_info "创建 ${swap_size}MB 交换文件..." + + if command -v fallocate &>/dev/null; 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" + echo "$SWAPFILE none swap sw 0 0" >> /etc/fstab + + log_success "交换文件创建完成" +} + +swap_remove() { + if ! swap_exists; then + log_warn "交换文件不存在" + return 0 + fi + + if ! confirm "确认删除交换文件"; then + return 0 + fi + + log_info "删除交换文件..." + + swapoff "$SWAPFILE" 2>/dev/null || true + sed -i "\|$SWAPFILE|d" /etc/fstab 2>/dev/null || true + rm -f "$SWAPFILE" + + sync + echo 3 > /proc/sys/vm/drop_caches 2>/dev/null || true + + log_success "交换文件删除完成" +} + +swap_show_info() { + echo + log_info "交换文件状态:" + if [[ -f "$SWAPFILE" ]]; then + local file_size_mb + file_size_mb=$(stat -c%s "$SWAPFILE" 2>/dev/null | awk '{printf "%.0f", $1/1024/1024}') + echo -e " 文件: ${GREEN}$SWAPFILE${NC}" + echo -e " 大小: ${GREEN}${file_size_mb}MB${NC}" + + if swapon --show 2>/dev/null | grep -q "$SWAPFILE"; then + local used_kb + used_kb=$(awk -v swapfile="$SWAPFILE" '$1 == swapfile {print $4}' /proc/swaps) + local used_mb=$((used_kb / 1024)) + echo -e " 状态: ${GREEN}激活${NC} (已使用: ${used_mb}MB)" + else + echo -e " 状态: ${YELLOW}未激活${NC}" + fi + + if ! grep -q "$SWAPFILE" /etc/fstab 2>/dev/null; then + echo -e " 持久化: ${YELLOW}未配置${NC}" + else + echo -e " 持久化: ${GREEN}已配置${NC}" + fi + else + echo -e " 状态: ${RED}未创建${NC}" + fi + + echo + log_info "系统内存信息:" + free -h | grep -E "Mem|Swap" | while read -r line; do + echo " $line" + done +} + +swap_menu() { + while true; do + clear + cat << 'EOF' +╔══════════════════════════════════════╗ +║ 交换文件管理 ║ +╚══════════════════════════════════════╝ +EOF + + if swap_exists; then + echo -e "${GREEN}状态: 已配置 ($(swap_get_info))${NC}" + else + echo -e "${RED}状态: 未配置${NC}" + fi + + cat << 'EOF' + +1. 创建交换文件 +2. 删除交换文件 +3. 显示详细信息 +0. 返回主菜单 +EOF + + echo + read -rp "请选择操作: " choice + + case "$choice" in + 1) + swap_create + pause + ;; + 2) + swap_remove + pause + ;; + 3) + swap_show_info + pause + ;; + 0) + return 0 + ;; + *) + log_error "无效选择" + sleep 1 + ;; + esac + done +} + +# ========== 常用工具管理模块 ========== +# 工具包定义 +declare -A TOOL_PACKAGES=( + ["openssh"]="openssh-server openssh-client:openssh-server openssh-client:openssh:openssh" + ["nfs"]="nfs-common:nfs-common:nfs-utils:nfs-utils" + ["ping"]="iputils-ping:iputils:iputils-ping:iputils" + ["vim"]="vim:vim:vim:vim" + ["net-tools"]="net-tools:net-tools:net-tools:net-tools" + ["htop"]="htop:htop:htop:htop" + ["tmux"]="tmux:tmux:tmux:tmux" + ["curl"]="curl:curl:curl:curl" + ["wget"]="wget:wget:wget:wget" + ["git"]="git:git:git:git" +) + +# 获取包名 (apt:yum/dnf:pacman:zypper) +get_package_name() { + local tool="$1" + local pm="$2" + local packages="${TOOL_PACKAGES[$tool]:-}" + + [[ -z "$packages" ]] && { echo "$tool"; return; } + + case "$pm" in + apt) echo "${packages%%:*}" ;; + yum|dnf) + local pkg="${packages#*:}" + echo "${pkg%%:*}" + ;; + pacman) + local pkg="${packages#*:*:}" + echo "${pkg%%:*}" + ;; + zypper) echo "${packages##*:}" ;; + *) echo "$tool" ;; + esac +} + +# 检查工具是否已安装 +tool_is_installed() { + local tool="$1" + case "$tool" in + openssh) + command -v sshd &>/dev/null && command -v ssh &>/dev/null + ;; + nfs) + command -v showmount &>/dev/null || systemctl list-unit-files | grep -q nfs + ;; + ping) + command -v ping &>/dev/null + ;; + net-tools) + command -v ifconfig &>/dev/null + ;; + *) + command -v "$tool" &>/dev/null + ;; + esac +} + +# 安装单个工具 +install_single_tool() { + local tool="$1" + local pm="$2" + local package + + package=$(get_package_name "$tool" "$pm") + + log_info "安装 $tool (包: $package)..." + + case "$pm" in + apt) + apt update -qq + apt install -y $package + ;; + yum) + yum install -y $package + ;; + dnf) + dnf install -y $package + ;; + pacman) + pacman -S --noconfirm $package + ;; + zypper) + zypper install -y $package + ;; + *) + log_error "不支持的包管理器: $pm" + return 1 + ;; + esac + + if tool_is_installed "$tool"; then + log_success "$tool 安装完成" + + # 启动相关服务 + case "$tool" in + openssh) + systemctl restart sshd 2>/dev/null || systemctl enable --now sshd 2>/dev/null || systemctl enable --now ssh 2>/dev/null || true + ;; + esac + return 0 + else + log_error "$tool 安装失败" + return 1 + fi +} + +# 批量安装工具 +install_tools() { + local pm + pm=$(detect_package_manager) + + if [[ "$pm" == "unknown" ]]; then + log_error "无法识别包管理器" + return 1 + fi + + local tools=(openssh nfs ping vim net-tools htop tmux curl wget git) + local selected_tools=() + + echo + log_info "可安装的工具:" + for i in "${!tools[@]}"; do + local tool="${tools[$i]}" + local status + if tool_is_installed "$tool"; then + status="${GREEN}已安装${NC}" + else + status="${RED}未安装${NC}" + fi + printf "%2d) %-12s %b\n" $((i+1)) "$tool" "$status" + done + + echo + echo "选择安装选项:" + echo " a) 安装全部" + echo " s) 选择安装" + echo " 0) 返回" + echo + read -rp "请选择: " choice + + case "$choice" in + a|A) + selected_tools=("${tools[@]}") + ;; + s|S) + echo + read -rp "请输入工具编号(用空格分隔,如: 1 3 5): " numbers + for num in $numbers; do + if [[ "$num" =~ ^[0-9]+$ ]] && [[ "$num" -ge 1 ]] && [[ "$num" -le "${#tools[@]}" ]]; then + selected_tools+=("${tools[$((num-1))]}") + fi + done + ;; + 0) + return 0 + ;; + *) + log_error "无效选择" + return 1 + ;; + esac + + if [[ ${#selected_tools[@]} -eq 0 ]]; then + log_warn "未选择任何工具" + return 0 + fi + + log_info "将安装: ${selected_tools[*]}" + if ! confirm "确认安装这些工具"; then + return 0 + fi + + local success_count=0 + for tool in "${selected_tools[@]}"; do + if tool_is_installed "$tool"; then + log_info "$tool 已安装,跳过" + ((success_count++)) + elif install_single_tool "$tool" "$pm"; then + ((success_count++)) + fi + done + + log_info "安装完成: ${success_count}/${#selected_tools[@]} 成功" +} + +# 卸载工具 +uninstall_tool() { + local pm + pm=$(detect_package_manager) + + local tools=(openssh nfs ping vim net-tools htop tmux curl wget git) + local installed_tools=() + + for tool in "${tools[@]}"; do + if tool_is_installed "$tool"; then + installed_tools+=("$tool") + fi + done + + if [[ ${#installed_tools[@]} -eq 0 ]]; then + log_warn "没有已安装的工具" + return 0 + fi + + echo + log_info "已安装的工具:" + for i in "${!installed_tools[@]}"; do + printf "%2d) %s\n" $((i+1)) "${installed_tools[$i]}" + done + + echo + read -rp "请输入要卸载的工具编号(用空格分隔): " numbers + + local selected_tools=() + for num in $numbers; do + if [[ "$num" =~ ^[0-9]+$ ]] && [[ "$num" -ge 1 ]] && [[ "$num" -le "${#installed_tools[@]}" ]]; then + selected_tools+=("${installed_tools[$((num-1))]}") + fi + done + + if [[ ${#selected_tools[@]} -eq 0 ]]; then + log_warn "未选择任何工具" + return 0 + fi + + if ! confirm "确认卸载这些工具: ${selected_tools[*]}"; then + return 0 + fi + + for tool in "${selected_tools[@]}"; do + local package + package=$(get_package_name "$tool" "$pm") + + log_info "卸载 $tool..." + case "$pm" in + apt) apt remove -y $package ;; + yum) yum remove -y $package ;; + dnf) dnf remove -y $package ;; + pacman) pacman -R --noconfirm $package ;; + zypper) zypper remove -y $package ;; + esac + + # 停止相关服务 + case "$tool" in + openssh) + systemctl disable --now sshd 2>/dev/null || systemctl disable --now ssh 2>/dev/null || true + ;; + esac + done + + log_success "卸载完成" +} + +# Tmux配置 +configure_tmux() { + if ! tool_is_installed "tmux"; then + log_error "tmux 未安装" + return 1 + fi + + log_info "配置 tmux..." + + # 备份现有配置 + [[ -f "$TMUX_CONFIG" ]] && cp "$TMUX_CONFIG" "${TMUX_CONFIG}.bak.$(date +%Y%m%d-%H%M-%S)" + + cat > "$TMUX_CONFIG" << 'EOF' +# Tmux 配置文件 +# 修改前缀键为 Ctrl+h +set -g prefix C-h +unbind C-b +bind C-h send-prefix + +# 重新加载配置文件 +bind r source-file ~/.tmux.conf \; display-message "Config reloaded.." + +# 分割面板快捷键 +unbind '"' +bind - splitw -v # 水平分割 +unbind % +bind | splitw -h # 垂直分割 + +# 调整面板大小 +bind -r ^k resizep -U 5 # 向上调整 +bind -r ^j resizep -D 5 # 向下调整 +bind -r ^h resizep -L 5 # 向左调整 +bind -r ^l resizep -R 5 # 向右调整 + +# 面板选择 +bind k selectp -U # 上面板 +bind j selectp -D # 下面板 +bind h selectp -L # 左面板 +bind l selectp -R # 右面板 + +# 同步面板 +bind-key s setw synchronize-panes + +# 基础设置 +set -g base-index 1 # 窗口起始序号 +set -g pane-base-index 1 # 面板起始序号 +set -g status-interval 1 # 状态栏刷新间隔 +set -g status-justify left # 状态栏对齐方式 +setw -g monitor-activity on # 监控窗口活动 +set -wg window-status-format " #I #W " # 窗口状态格式 +set -wg window-status-current-format " #I:#W#F " # 当前窗口格式 +set -wg window-status-separator "" # 窗口分隔符 +set-window-option -g mode-keys vi # Vi 模式 +set -g history-limit 500000 # 历史记录限制 + +# 颜色配置 +set-option -g default-terminal "screen-256color" +set -g status-style fg=white,bg=black +setw -g window-status-style fg=cyan +setw -g window-status-current-style fg=white,bg=magenta +set -g pane-border-style fg=white +set -g pane-active-border-style fg=magenta +set -g message-style fg=colour186,bg=black,bright + +# 状态栏配置 +set -g status-left "#[fg=green]#S#[fg=yellow]-#I#[fg=cyan]-#P" +set -g status-justify centre +setw -g monitor-activity on +set -g visual-activity on +EOF + + log_success "tmux 配置完成" + log_info "配置文件: $TMUX_CONFIG" + log_info "使用 'tmux source ~/.tmux.conf' 重新加载配置" +} + +# Vim配置 +configure_vim() { + if ! tool_is_installed "vim"; then + log_error "vim 未安装" + return 1 + fi + + log_info "配置 vim..." + + # 备份现有配置 + [[ -f "$VIM_CONFIG" ]] && cp "$VIM_CONFIG" "${VIM_CONFIG}.bak.$(date +%Y%m%d-%H%M-%S)" + + cat > "$VIM_CONFIG" << 'EOF' +" Vim 基础配置 +" 显示设置 +set number " 显示行号 +set relativenumber " 相对行号 +set cursorline " 高亮当前行 +set showmatch " 显示匹配括号 +set ruler " 显示光标位置 +set laststatus=2 " 始终显示状态栏 + +" 搜索设置 +set hlsearch " 高亮搜索结果 +set incsearch " 增量搜索 +set ignorecase " 忽略大小写 +set smartcase " 智能大小写 + +" 编辑设置 +set paste +" set autoindent " 自动缩进 +" set smartindent " 智能缩进 +set expandtab " Tab转空格 +set tabstop=4 " Tab宽度 +set shiftwidth=4 " 缩进宽度 +set softtabstop=4 " 软Tab宽度 + +" 界面设置 +set wildmenu " 命令行补全菜单 +set scrolloff=5 " 滚动偏移 +set encoding=utf-8 " 编码设置 +set fileencodings=utf-8,gb2312,gb18030,gbk,ucs-bom,cp936,latin1 + +" 功能设置 +set mouse=a " 启用鼠标 +set clipboard=unnamed " 系统剪贴板 +set backspace=2 " 退格键设置 +set noswapfile " 不创建交换文件 +set nobackup " 不创建备份文件 + +" 颜色方案 +syntax on " 语法高亮 +colorscheme default " 默认配色 + +" 快捷键映射 +nnoremap h " 窗口切换 +nnoremap j +nnoremap k +nnoremap l +EOF + + log_success "vim 配置完成" + log_info "配置文件: $VIM_CONFIG" +} + +# 工具配置菜单 +configure_tools() { + while true; do + clear + cat << 'EOF' +╔══════════════════════════════════════╗ +║ 工具配置 ║ +╚══════════════════════════════════════╝ +EOF + + echo + printf "1. 配置 tmux" + if [[ -f "$TMUX_CONFIG" ]]; then + echo -e " ${GREEN}(已配置)${NC}" + else + echo -e " ${RED}(未配置)${NC}" + fi + + printf "2. 配置 vim" + if [[ -f "$VIM_CONFIG" ]]; then + echo -e " ${GREEN}(已配置)${NC}" + else + echo -e " ${RED}(未配置)${NC}" + fi + + cat << 'EOF' +3. 查看配置文件 +4. 恢复默认配置 +0. 返回上级菜单 +EOF + + echo + read -rp "请选择操作: " choice + + case "$choice" in + 1) + configure_tmux + pause + ;; + 2) + configure_vim + pause + ;; + 3) + echo + echo "配置文件位置:" + echo " tmux: $TMUX_CONFIG" + echo " vim: $VIM_CONFIG" + pause + ;; + 4) + echo + echo "可恢复的配置:" + if ls "${TMUX_CONFIG}".backup.* &>/dev/null; then + echo " 1) tmux 备份文件存在" + fi + if ls "${VIM_CONFIG}".backup.* &>/dev/null; then + echo " 2) vim 备份文件存在" + fi + echo " 请手动删除配置文件或重命名备份文件" + pause + ;; + 0) + return 0 + ;; + *) + log_error "无效选择" + sleep 1 + ;; + esac + done +} + +# 工具管理主菜单 +tools_menu() { + while true; do + clear + cat << 'EOF' +╔══════════════════════════════════════╗ +║ 常用工具管理 ║ +╚══════════════════════════════════════╝ +EOF + + echo + local pm + pm=$(detect_package_manager) + echo -e "包管理器: ${GREEN}$pm${NC}" + local tools=(openssh nfs ping vim net-tools htop tmux curl wget git) + local installed_count=0 + for tool in "${tools[@]}"; do + if tool_is_installed "$tool"; then + ((installed_count++)) + fi + done + echo -e "已安装工具: ${GREEN}${installed_count}${NC}/${#tools[@]}" + + cat << 'EOF' + +1. 安装工具 +2. 卸载工具 +3. 工具状态 +4. 工具配置 +0. 返回主菜单 +EOF + + echo + read -rp "请选择操作: " choice + + case "$choice" in + 1) + install_tools + pause + ;; + 2) + uninstall_tool + pause + ;; + 3) + echo + log_info "工具安装状态:" + for tool in "${tools[@]}"; do + if tool_is_installed "$tool"; then + echo -e " ${tool}: ${GREEN}已安装${NC}" + else + echo -e " ${tool}: ${RED}未安装${NC}" + fi + done + pause + ;; + 4) + configure_tools + ;; + 0) + return 0 + ;; + *) + log_error "无效选择" + sleep 1 + ;; + esac + done +} + + +# ========== 系统源更换模块 ========== +set_linux_mirrors() { + log_info "开始更换系统源..." + + if ! command -v curl &>/dev/null; then + log_error "需要 curl 工具,请先安装" + if confirm "是否立即安装 curl"; then + local pm + pm=$(detect_package_manager) + install_single_tool "curl" "$pm" + else + return 1 + fi + fi + + log_info "下载并执行系统源更换脚本..." + log_warn "注意: 此操作将修改您的系统软件源配置" + log_warn "建议在操作前备份重要数据" + + if ! confirm "确认继续执行系统源更换操作"; then + return 0 + fi + + # 执行系统源更换脚本 + if bash <(curl -sSL https://linuxmirrors.cn/main.sh); then + log_success "系统源更换完成" + log_info "建议运行系统更新命令以应用新源" + + local pm + pm=$(detect_package_manager) + case "$pm" in + apt) log_info "请运行: apt update && apt upgrade -y" ;; + yum|dnf) log_info "请运行: $pm update -y" ;; + pacman) log_info "请运行: pacman -Syu" ;; + zypper) log_info "请运行: zypper refresh && zypper update -y" ;; + esac + else + log_error "系统源更换失败" + return 1 + fi +} + + +# ========== 主程序 ========== +show_system_info() { + clear + cat << 'EOF' +╔══════════════════════════════════════╗ +║ Linux 系统管理工具 ║ +╚══════════════════════════════════════╝ +EOF + + echo + log_info "系统信息:" + echo " OS: $(uname -o) $(uname -r)" + echo " 内存: $(free -h | awk '/^Mem:/ {print $2}')" + echo " 磁盘: $(df -h / | awk 'NR==2 {print $4}') 可用" + + echo + log_info "服务状态:" + printf " Docker: " + if docker_check_installed; then + echo -e "${GREEN}已安装 (v$(docker_get_version))${NC}" + else + echo -e "${RED}未安装${NC}" + fi + + printf " 交换文件: " + if swap_exists; then + echo -e "${GREEN}已配置 ($(swap_get_info))${NC}" + else + echo -e "${RED}未配置${NC}" + fi + + # 显示常用工具状态 + local tools=(vim htop tmux git) + local installed_tools=() + for tool in "${tools[@]}"; do + if tool_is_installed "$tool"; then + installed_tools+=("$tool") + fi + done + printf " 常用工具: " + if [[ ${#installed_tools[@]} -gt 0 ]]; then + echo -e "${GREEN}${installed_tools[*]}${NC}" + else + echo -e "${RED}未安装${NC}" + fi + + echo +} + +main_menu() { + while true; do + show_system_info + cat << 'EOF' +1. Docker 管理 +2. 交换文件管理 +3. 常用工具管理 +4. 更换系统源 +9. 系统信息 +10. 查看日志 +0. 退出程序 +EOF + + echo + read -rp "请选择功能模块: " choice + + case "$choice" in + 1) + docker_menu + ;; + 2) + if check_virtualization; then + swap_menu + else + log_error "当前环境不支持交换文件功能" + pause + fi + ;; + 3) + tools_menu + ;; + 4) + set_linux_mirrors + ;; + 9) + show_system_info + pause + ;; + 10) + if [[ -f "$LOG_FILE" ]]; then + echo + echo "=== 日志文件最后20行 ===" + tail -20 "$LOG_FILE" + else + echo "暂无日志" + fi + pause + ;; + 0) + log_info "再见!" + exit 0 + ;; + *) + log_error "无效选择" + sleep 1 + ;; + esac + done +} + +# 程序入口 +main() { + check_root + + # 创建日志文件 + touch "$LOG_FILE" + + log "系统管理工具启动" + main_menu +} + +main