#!/bin/bash #set -e # ============ 平台检测 ============= detect_platform() { case "$(uname -s)" in Darwin) OS="macOS" SHA_TOOL="shasum" OPEN_CMD="open" DATE_PARSER="mac" FILE_VMOPTIONS=".vmoptions" ;; Linux) OS="Linux" SHA_TOOL="sha1sum" OPEN_CMD="xdg-open" DATE_PARSER="linux" FILE_VMOPTIONS="64.vmoptions" ;; *) OS="Unknown" SHA_TOOL="sha1sum" OPEN_CMD="xdg-open" DATE_PARSER="linux" FILE_VMOPTIONS=".vmoptions" ;; esac } # 自动检测平台 detect_platform # ============ 语言检测 ============= detect_language() { local lang=${LANG:-} if [[ $lang == zh* ]]; then LANGUAGE="zh" else LANGUAGE="en" fi } detect_language # ============ 国际化支持 ============= # 初始化国际化字符串 init_i18n_strings() { # processing_env_vars processing_env_vars_zh="处理 {0} 环境变量" processing_env_vars_en="Processing {0} environment variables" # checking_env checking_env_zh="检查 [{0}]: {1} = '{2}'" checking_env_en="Checking [{0}]: {1} = '{2}'" # deleting_env deleting_env_zh="删除 [{0}]: {1}" deleting_env_en="Deleting [{0}]: {1}" # welcome_msg welcome_msg_zh="欢迎使用 JetBrains 激活工具 | jb" welcome_msg_en="Welcome to JetBrains Activation Tool | jb" # script_date script_date_zh="脚本日期:2025-12-10" script_date_en="Script Date: 2025-12-10" # warning_msg warning_msg_zh="注意,执行脚本默认会将所有产品全部激活一遍,无论之前是否激活过!!!" warning_msg_en="Warning: This script will forcibly re-activate all products!!!" # close_products close_products_zh="请确保激活的软件处于关闭状态,请按回车继续..." close_products_en="Please make sure all JetBrains software is closed, press Enter to continue..." # processing processing_zh="处理中,请耐心等待..." processing_en="Processing, please wait patiently..." # processing_configs processing_configs_zh="开始处理配置..." processing_configs_en="Starting to process configurations..." # not_found_dir not_found_dir_zh="未找到 {0} 目录!" not_found_dir_en="Directory not found: {0}!" # processing_product processing_product_zh="处理: {0}" processing_product_en="Processing: {0}" # not_found_home not_found_home_zh="未找到 .home 文件: {0}" not_found_home_en=".home file not found: {0}" # path_not_exist path_not_exist_zh="路径不存在: {0}" path_not_exist_en="Path does not exist: {0}" # not_found_bin not_found_bin_zh="未找到 bin 目录: {0}" not_found_bin_en="bin directory not found: {0}" # config_exists_cleaning config_exists_cleaning_zh="{0} 配置文件已存在,正在清理..." config_exists_cleaning_en="{0} configuration file already exists, cleaning..." # key_exists_cleaning key_exists_cleaning_zh="key已存在,正在清理..." key_exists_cleaning_en="Key already exists, cleaning..." # activation_success activation_success_zh="{0} 激活成功!" activation_success_en="{0} activated successfully!" # manual_activation_required manual_activation_required_zh="{0} 需要手动输入激活码!" manual_activation_required_en="{0} requires manual activation code entry!" # download_failed download_failed_zh="下载失败: {0}" download_failed_en="Download failed: {0}" # request_failed request_failed_zh="{0} 请求失败: {1}" request_failed_en="{0} request failed: {1}" # file_in_use file_in_use_zh="文件被占用,请先关闭所有 JetBrains IDE 后再试!" file_in_use_en="File is in use, please close all JetBrains IDEs and try again!" # processing_completed processing_completed_zh="所有项处理结束,如需要激活码,请前往网站获取!" processing_completed_en="All items processed. If you need an activation code, please visit the website!" # format_error format_error_zh="格式错误:请使用 yyyy-MM-dd 格式" format_error_en="Format error: Please use yyyy-MM-dd format" # invalid_date invalid_date_zh="非法日期:{0}" invalid_date_en="Invalid date: {0}" # reading_config reading_config_zh="读取配置文件:{0}, 寻找键:{1}" reading_config_en="Reading config file: {0}, looking for key: {1}" # found_key found_key_zh="找到键 '{0}',值为 '{1}'" found_key_en="Found key '{0}' with value '{1}'" # failed_read_config failed_read_config_zh="读取配置文件失败:{0}" failed_read_config_en="Failed to read config file: {0}" # cleaning_vmoptions cleaning_vmoptions_zh="清理 VMOptions: {0}" cleaning_vmoptions_en="Cleaning VMOptions: {0}" # updating_vmoptions updating_vmoptions_zh="更新 VMOptions: {0}" updating_vmoptions_en="Updating VMOptions: {0}" # processing_disabled_plugins processing_disabled_plugins_zh="已处理文件: {0} 中com.intellij.modules.ultimate项" processing_disabled_plugins_en="Processed file: {0} com.intellij.modules.ultimate item" # file_not_exist_skip file_not_exist_skip_zh="文件不存在,跳过: {0}" file_not_exist_skip_en="File does not exist, skipping: {0}" # error_processing_plugins error_processing_plugins_zh="处理禁用插件文件时出错: {0}" error_processing_plugins_en="Error processing disabled plugins file: {0}" # processing_config processing_config_zh="处理配置: {0}, {1}, {2}" processing_config_en="Processing config: {0}, {1}, {2}" # requesting_key requesting_key_zh="请求key: {0},请求body: {1},保存地址: {2}" requesting_key_en="Requesting key: {0}, request body: {1}, save path: {2}" # writing_key writing_key_zh="写入key,激活中: {0}" writing_key_en="Writing key, activating: {0}" # source_address source_address_zh="源ja-netfilter项目地址: https://gitee.com/ja-netfilter/ja-netfilter/releases/tag/2025.3.0" source_address_en="Source ja-netfilter address: https://gitee.com/ja-netfilter/ja-netfilter/releases/tag/2025.3.0" # source_privacy source_privacy_zh="源 privacy.jar 地址: https://gitea.998043.xyz/novice/plugin-privacy/releases/tag/release" source_privacy_en="Source privacy.jar address: https://gitea.998043.xyz/novice/plugin-privacy/releases/tag/release" # suggest_check_sha1 suggest_check_sha1_zh="如需检查下载的.jar是否被篡改请核对sha1的值是否与源项目文件一致" suggest_check_sha1_en="It is recommended to verify the SHA1 value to ensure integrity" # configuring_ja_netfilter configuring_ja_netfilter_zh="配置 ja-netfilter..." configuring_ja_netfilter_en="Configuring ja-netfilter..." # custom_license_name custom_license_name_zh="自定义授权名称 (回车默认 jb)" custom_license_name_en="Custom license name (Enter for default jb)" # custom_expiry_date custom_expiry_date_zh="自定义授权日期 (回车默认 2999-12-31, 格式 yyyy-MM-dd)" custom_expiry_date_en="Custom expiration date (Enter for default 2999-12-31, format yyyy-MM-dd)" # default_license_name default_license_name="jb" # default_expiry_date default_expiry_date="2999-12-31" # file_path_empty file_path_empty_zh="文件路径为空,跳过处理" file_path_empty_en="File path is empty, skipping processing" # found_home_file found_home_file_zh="找到.home文件: {0}" found_home_file_en="Found .home file: {0}" # read_home_content read_home_content_zh="读取.home文件内容: {0}" read_home_content_en="Read .home file content: {0}" # found_bin_dir found_bin_dir_zh="找到bin目录: {0}" found_bin_dir_en="Found bin directory: {0}" # sha1_info sha1_info="{0} :sha1: {1}" # request_fail request_fail_zh="请求失败: {0}" request_fail_en="Request failed: {0}" # all_deps_installed all_deps_installed_zh="所有依赖已安装。" all_deps_installed_en="All dependencies are installed." # missing_deps missing_deps_zh="缺少以下依赖:{0},正在尝试自动安装..." missing_deps_en="Missing dependencies: {0}, trying to install automatically..." # homebrew_not_found homebrew_not_found_zh="检测到 macOS但未安装 Homebrew" homebrew_not_found_en="Detected macOS but Homebrew is not installed" # install_homebrew_prompt install_homebrew_prompt_zh="是否要自动安装 Homebrew?(y/n) " install_homebrew_prompt_en="Do you want to install Homebrew automatically? (y/n) " # installing_homebrew installing_homebrew_zh="正在安装 Homebrew..." installing_homebrew_en="Installing Homebrew..." # homebrew_post_install homebrew_post_install_zh="Homebrew 安装后仍不可用,请手动重启终端后重试" homebrew_post_install_en="Homebrew is still not available after installation, please restart the terminal and try again" # homebrew_required homebrew_required_zh="必须安装 Homebrew 才能继续!" homebrew_required_en="Homebrew must be installed to continue!" # installing_deps_with_brew installing_deps_with_brew_zh="使用 Homebrew 安装依赖" installing_deps_with_brew_en="Installing dependencies with Homebrew" # unrecognized_linux_distro unrecognized_linux_distro_zh="无法识别的 Linux 发行版,请手动安装依赖:{0}" unrecognized_linux_distro_en="Unrecognized Linux distribution, please manually install dependencies: {0}" # unsupported_os unsupported_os_zh="不支持的操作系统" unsupported_os_en="Unsupported operating system" # install_failed install_failed_zh="安装失败:{0}" install_failed_en="Installation failed: {0}" # all_deps_installed_success all_deps_installed_success_zh="所有依赖已成功安装!" all_deps_installed_success_en="All dependencies have been successfully installed!" # env_cleanup_start env_cleanup_start_zh="开始清理 JetBrains 相关环境变量" env_cleanup_start_en="Start cleaning JetBrains related environment variables" # no_env_files_found no_env_files_found_zh="未找到任何环境变量文件,跳过" no_env_files_found_en="No environment variable files found, skipping" # file_not_writable file_not_writable_zh="文件 {0} 不可写,跳过修改" file_not_writable_en="File {0} is not writable, skipping modification" # backup_env_file backup_env_file_zh="备份环境变量文件: {0}, {1}, {2}" backup_env_file_en="Backup environment variable file: {0}, {1}, {2}" # removing_env_var removing_env_var_zh="删除环境变量: {0},{1}" removing_env_var_en="Removing environment variable: {0},{1}" # other_tools_env_cleanup other_tools_env_cleanup_zh="清理三方工具环境变量完成" other_tools_env_cleanup_en="Cleanup of third-party tool environment variables completed" # enter_license_name enter_license_name_zh="自定义授权名称 (回车默认 jb): " enter_license_name_en="Custom license name (Enter for default jb): " # enter_expiry_date enter_expiry_date_zh="自定义授权日期 (回车默认 {0}, 格式 yyyy-MM-dd): " enter_expiry_date_en="Custom expiration date (Enter for default {0}, format yyyy-MM-dd): " # entered_expiry_date entered_expiry_date_zh="输入的授权日期: {0}" entered_expiry_date_en="Entered expiration date: {0}" # invalid_date_format invalid_date_format_zh="日期格式不合法,请输入正确的 yyyy-MM-dd 格式(例如:2999-12-31)" invalid_date_format_en="Invalid date format, please enter the correct yyyy-MM-dd format (e.g. 2999-12-31)" # illegal_path_detected illegal_path_detected_zh="检测到非法路径: {0},请检查配置。" illegal_path_detected_en="Illegal path detected: {0}, please check configuration." # creating_work_dirs creating_work_dirs_zh="创建工作目录: {0}" creating_work_dirs_en="Creating work directories: {0}" # download_progress download_progress_zh="正在下载: {0} -> {1}" download_progress_en="Downloading: {0} -> {1}" # sha1_verification_skipped sha1_verification_skipped_zh="未找到 {0} 工具,跳过 SHA-1 校验" sha1_verification_skipped_en="{0} tool not found, skipping SHA-1 verification" # cleaning_vm_file cleaning_vm_file_zh="清理vm: {0}" cleaning_vm_file_en="Cleaning vm: {0}" # cleaning_vm_file_not_exist cleaning_vm_file_not_exist_zh="清理vm: 文件不存在,跳过清理: {0}" cleaning_vm_file_not_exist_en="Cleaning vm: File does not exist, skipping cleanup: {0}" # generating_vm_file generating_vm_file_zh="生成vm: {0}" generating_vm_file_en="Generating vm: {0}" # generating_vm_file_failed generating_vm_file_failed_zh="生成vm: 创建失败: {0}" generating_vm_file_failed_en="Generating vm: Failed to create: {0}" # processing_disabled_plugins_file processing_disabled_plugins_file_zh="已处理文件 {0} 中com.intellij.modules.ultimate 项" processing_disabled_plugins_file_en="Processed com.intellij.modules.ultimate item in file {0}" # url_license_params url_license_params="URL_LICENSE:{0},params:{1},save_path:{2}" # home_path home_path_zh=".home路径: {0}" home_path_en=".home path: {0}" # home_content home_content_zh=".home内容: {0}" home_content_en=".home content: {0}" # bin_dir_not_exist bin_dir_not_exist_zh="{0} 的 bin 目录不存在,请确认是否正确安装!" bin_dir_not_exist_en="The bin directory of {0} does not exist, please confirm if it is installed correctly!" # vmoptions_not_found_creating vmoptions_not_found_creating_zh="未找到{0} 的.vmoptions文件,将创建一个默认的" vmoptions_not_found_creating_en=".vmoptions file for {0} not found, will create a default one" # config_dir config_dir_zh="config目录:{0}" config_dir_en="config directory: {0}" # dir_not_found dir_not_found_zh="未找到{0}目录" dir_not_found_en="Directory {0} not found" } # 获取国际化字符串 get_i18n_string() { local key="$1" local var_name="${key}_${LANGUAGE}" # 使用间接引用获取变量值 if [[ -n "${!var_name}" ]]; then echo "${!var_name}" else # 如果找不到对应语言的字符串,返回键名本身 echo "${!key}" fi } # 格式化字符串(最多支持3个参数) format_string() { local template="$1" local arg1="$2" local arg2="$3" local arg3="$4" # 替换 {0}, {1}, {2} 占位符 local result="$template" result="${result//\{0\}/$arg1}" result="${result//\{1\}/$arg2}" result="${result//\{2\}/$arg3}" echo "$result" } # 初始化国际化字符串字典 init_i18n_strings # ============ 配置 ============= DEBUG=false ENABLE_COLOR=true URL_BASE="https://jb.900198.xyz" #URL_BASE="http://192.168.31.254:10768" URL_DOWNLOAD="${URL_BASE}/ja-netfilter" URL_LICENSE="${URL_BASE}/generateLicense/file" # 获取原始用户和家目录 if [ "$(id -u)" -eq 0 ] && [ -n "$SUDO_USER" ]; then ORIGINAL_USER="$SUDO_USER" USER_HOME="/home/${SUDO_USER}" else ORIGINAL_USER="$(whoami)" USER_HOME="${HOME}" fi # macOS 用户路径修正 if [[ "$OS" == "macOS" ]]; then USER_HOME="/Users/${ORIGINAL_USER}" fi # 工作路径 dir_work="${USER_HOME}/.jb_run" dir_config="${dir_work}/config" dir_plugins="${dir_work}/plugins" dir_backups="${dir_work}/backups" file_netfilter_jar="${dir_work}/ja-netfilter.jar" # JetBrains 目录 if [[ "$OS" == "macOS" ]]; then dir_cache_jb="${USER_HOME}/Library/Caches/JetBrains" dir_config_jb="${USER_HOME}/Library/Application Support/JetBrains" else dir_cache_jb="${USER_HOME}/.cache/JetBrains" dir_config_jb="${USER_HOME}/.config/JetBrains" fi # 日志颜色设置 if $ENABLE_COLOR; then RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' GRAY='\033[38;5;240m' NC='\033[0m' else RED='' GREEN='' YELLOW='' GRAY='' NC='' fi # 产品列表 PRODUCTS='[ {"name":"idea","productCode":"II,PCWMP,PSI"}, {"name":"clion","productCode":"CL,PSI,PCWMP"}, {"name":"phpstorm","productCode":"PS,PCWMP,PSI"}, {"name":"goland","productCode":"GO,PSI,PCWMP"}, {"name":"pycharm","productCode":"PC,PSI,PCWMP"}, {"name":"webstorm","productCode":"WS,PCWMP,PSI"}, {"name":"rider","productCode":"RD,PDB,PSI,PCWMP"}, {"name":"datagrip","productCode":"DB,PSI,PDB"}, {"name":"rubymine","productCode":"RM,PCWMP,PSI"}, {"name":"appcode","productCode":"AC,PCWMP,PSI"}, {"name":"dataspell","productCode":"DS,PSI,PDB,PCWMP"}, {"name":"rustrover","productCode":"RR,PSI,PCWP"} ]' # ============ 工具函数 ============= # ============ 日期验证 ============= check_and_install_deps() { local deps=("curl" "jq") local missing=() for dep in "${deps[@]}"; do if ! command -v "$dep" &>/dev/null; then missing+=("$dep") fi done if [ ${#missing[@]} -eq 0 ]; then info "all_deps_installed" return fi local missing_str=$(IFS=", "; echo "${missing[*]}") warning "missing_deps" "$missing_str" # 先检测系统类型 case "$(uname -s)" in Darwin) # 检测 Homebrew 是否存在 if ! command -v brew &>/dev/null; then warning "homebrew_not_found" local prompt_msg=$(get_i18n_string "install_homebrew_prompt") read -p "$prompt_msg" install_brew if [[ "$install_brew" =~ [yY] ]]; then info "installing_homebrew" /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" # 自动配置环境变量 if [ -x "/opt/homebrew/bin/brew" ]; then # Apple Silicon echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zshrc source ~/.zshrc elif [ -x "/usr/local/bin/brew" ]; then # Intel echo 'eval "$(/usr/local/bin/brew shellenv)"' >> ~/.zshrc source ~/.zshrc fi # 再次验证 if ! command -v brew &>/dev/null; then error "homebrew_post_install" exit 1 fi else error "homebrew_required" exit 1 fi fi # 安装依赖 info "installing_deps_with_brew" brew install "${missing[@]}" ;; Linux) # Linux 系统 (原逻辑) if command -v apt-get &>/dev/null; then sudo apt update && sudo apt install -y "${missing[@]}" elif command -v dnf &>/dev/null; then sudo dnf install -y "${missing[@]}" elif command -v yum &>/dev/null; then sudo yum install -y "${missing[@]}" elif command -v pacman &>/dev/null; then sudo pacman -Sy --noconfirm "${missing[@]}" else error "unrecognized_linux_distro" "$missing_str" exit 1 fi ;; *) error "unsupported_os" exit 1 ;; esac # 验证安装结果 for dep in "${missing[@]}"; do if ! command -v "$dep" &>/dev/null; then error "install_failed" "$dep" exit 1 fi done success "all_deps_installed_success" } # ============ 解析产品 ============= parse_product_from_json() { local index="$1" local name=$(echo "$PRODUCTS" | jq -r ".[$index].name") local code=$(echo "$PRODUCTS" | jq -r ".[$index].productCode") echo "$name|$code" } # ============ 日志函数 ============= log() { local level="$1" local message="$2" local color="" case "$level" in "INFO") color="$NC" ;; "DEBUG") [[ "$DEBUG" == true ]] || return color="$GRAY" ;; "WARNING") color="$YELLOW" ;; "ERROR") color="$RED" ;; "SUCCESS") color="$GREEN" ;; *) color="$NC" ;; esac echo -e "${color}[$(date '+%Y-%m-%d %H:%M:%S')][$level] ${message}${NC}" } debug() { local msg=$(get_i18n_string "$1") if [[ $# -gt 1 ]]; then msg=$(format_string "$msg" "$2" "$3" "$4") fi log "DEBUG" "$msg" } info() { local msg=$(get_i18n_string "$1") if [[ $# -gt 1 ]]; then msg=$(format_string "$msg" "$2" "$3" "$4") fi log "INFO" "$msg" } warning() { local msg=$(get_i18n_string "$1") if [[ $# -gt 1 ]]; then msg=$(format_string "$msg" "$2" "$3" "$4") fi log "WARNING" "$msg" } error() { local msg=$(get_i18n_string "$1") if [[ $# -gt 1 ]]; then msg=$(format_string "$msg" "$2" "$3" "$4") fi log "ERROR" "$msg" } success() { local msg=$(get_i18n_string "$1") if [[ $# -gt 1 ]]; then msg=$(format_string "$msg" "$2" "$3" "$4") fi log "SUCCESS" "$msg" } # ============ ASCII Art ============= show_ascii_jb() { cat <<'EOF' JJJJJJ EEEEEEE TTTTTTTT BBBBBBB RRRRRR AAAAAA IIIIIIII NNNN NN SSSSSS JJ EE TT BB BB RR RR AA AA II NNNNN NN SS JJ EE TT BB BB RR RR AA AA II NN NNN NN SS JJ EEEEE TT BBBBBBB RRRRRR AAAAAA II NN NNNNN SSSSS JJ EE TT BB BB RR RR AA AA II NN NNNN SS JJ JJ EE TT BB BB RR RR AA AA II NN NNN SS JJJJ EEEEEEE TT BBBBBBB RR RR AA AA IIIIIIII NN NNN SSSSSS EOF } # ============ 清理环境变量 ============= #清理其它工具产留 remove_env_other(){ OS_NAME=$(uname -s) JB_PRODUCTS="idea clion phpstorm goland pycharm webstorm webide rider datagrip rubymine appcode dataspell gateway jetbrains_client jetbrainsclient" KDE_ENV_DIR="${USER_HOME}/.config/plasma-workspace/env" PROFILE_PATH="${USER_HOME}/.profile" ZSH_PROFILE_PATH="${USER_HOME}/.zshrc" PLIST_PATH="${USER_HOME}/Library/LaunchAgents/jetbrains.vmoptions.plist" if [ $OS_NAME = "Darwin" ]; then BASH_PROFILE_PATH="${USER_HOME}/.bash_profile" else BASH_PROFILE_PATH="${USER_HOME}/.bashrc" fi touch "${PROFILE_PATH}" touch "${BASH_PROFILE_PATH}" touch "${ZSH_PROFILE_PATH}" MY_VMOPTIONS_SHELL_NAME="jetbrains.vmoptions.sh" MY_VMOPTIONS_SHELL_FILE="${USER_HOME}/.${MY_VMOPTIONS_SHELL_NAME}" rm -rf "${MY_VMOPTIONS_SHELL_FILE}" if [ $OS_NAME = "Darwin" ]; then for PRD in $JB_PRODUCTS; do ENV_NAME=$(echo $PRD | tr '[a-z]' '[A-Z]')"_VM_OPTIONS" launchctl unsetenv "${ENV_NAME}" done rm -rf "${PLIST_PATH}" sed -i '' '/___MY_VMOPTIONS_SHELL_FILE="${HOME}\/\.jetbrains\.vmoptions\.sh"; if /d' "${PROFILE_PATH}" >/dev/null 2>&1 sed -i '' '/___MY_VMOPTIONS_SHELL_FILE="${HOME}\/\.jetbrains\.vmoptions\.sh"; if /d' "${BASH_PROFILE_PATH}" >/dev/null 2>&1 sed -i '' '/___MY_VMOPTIONS_SHELL_FILE="${HOME}\/\.jetbrains\.vmoptions\.sh"; if /d' "${ZSH_PROFILE_PATH}" >/dev/null 2>&1 else sed -i '/___MY_VMOPTIONS_SHELL_FILE="${HOME}\/\.jetbrains\.vmoptions\.sh"; if /d' "${PROFILE_PATH}" >/dev/null 2>&1 sed -i '/___MY_VMOPTIONS_SHELL_FILE="${HOME}\/\.jetbrains\.vmoptions\.sh"; if /d' "${BASH_PROFILE_PATH}" >/dev/null 2>&1 sed -i '/___MY_VMOPTIONS_SHELL_FILE="${HOME}\/\.jetbrains\.vmoptions\.sh"; if /d' "${ZSH_PROFILE_PATH}" >/dev/null 2>&1 rm -rf "${KDE_ENV_DIR}/${MY_VMOPTIONS_SHELL_NAME}" fi debug "other_tools_env_cleanup" } remove_env_item_vars() { local shell_files=( "${USER_HOME}/.bash_profile" "${USER_HOME}/.bashrc" "${USER_HOME}/.zshrc" "${USER_HOME}/.profile" ) # 解析产品 local index=0 local product_count=$(echo "$PRODUCTS" | jq length) # 先过滤出实际存在的文件 local existing_files=() for file in "${shell_files[@]}"; do [ -f "$file" ] && existing_files+=("$file") done # 如果没有存在的文件则直接返回 [ ${#existing_files[@]} -eq 0 ] && { debug "no_env_files_found" return } # 环境变量备份目录 local dir_date_backup="$dir_backups/$(date +%s)" for file in "${existing_files[@]}"; do # 判断文件中是否包含指定环境变量 if [ ! -w "$file" ]; then warning "file_not_writable" "$file" >&2 continue fi # 备份环境变量文件到dir_backups/时间 if [ ! -d "$dir_date_backup" ]; then mkdir -p "$dir_date_backup" fi cp "$file" "${dir_date_backup}/_$(basename ${file})" debug "backup_env_file" "$file" "$dir_date_backup" "_$(basename ${file})" # 检测环境变量配置文件 local index=0 while [ $index -lt $product_count ]; do IFS='|' read -r name code <<< "$(parse_product_from_json "$index")" if [ -z "$name" ]; then break fi local upper_key="$(echo "${name}" | tr '[:lower:]' '[:upper:]')_VM_OPTIONS" # 判断file里面是否包含upper_key if grep -q "^${upper_key}" "$file"; then sed -i -E "/${upper_key}/d" "$file" debug "removing_env_var" "$file" "$upper_key" fi ((index++)) done source "$file" done } remove_env_vars() { info "env_cleanup_start" remove_env_item_vars # 删除其它激活工具残留 remove_env_other } # ============ 用户输入授权信息 ============= validate_date_format() { local input="$1" # 第一步:检查是否符合 yyyy-MM-dd 格式 if [[ ! "$input" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then warning "format_error" return 1 fi # 第二步:直接返回原值(无需调用 date 验证真实性) echo "$input" return 0 } read_license_info() { local enter_license_name_msg=$(get_i18n_string "enter_license_name") read -p "$enter_license_name_msg" license_name license_name=${license_name:-jb} local default_expiry="2999-12-31" local expiry_input local valid=false while [ "$valid" == "false" ]; do local enter_expiry_date_msg=$(get_i18n_string "enter_expiry_date") read -p "$(format_string "$enter_expiry_date_msg" "$default_expiry") " expiry_input expiry_input=${expiry_input:-$default_expiry} debug "entered_expiry_date" "$expiry_input" if expiry=$(validate_date_format "$expiry_input"); then expiry="$expiry" valid=true else warning "invalid_date_format" fi done LICENSE_JSON=$(cat </dev/null; then sha1_hash=$($SHA_TOOL "$file_save_path" | awk '{print $1}') else warning "sha1_verification_skipped" "$SHA_TOOL" return fi debug "sha1_info" "$url" "$sha1_hash \n" fi } progress_bar() { # 如果处于DEBUG模式,则不显示进度条 if [ "$DEBUG" = true ]; then return fi local current=$1 local total=$2 local bar_length=30 local percent=$((current * 100 / total)) local filled=$((percent * bar_length / 100)) local bar="[" bar+=$(printf '#%.0s' $(seq 1 $filled)) bar+=$(printf '.%.0s' $(seq 1 $((bar_length - filled)))) bar+="]" local configuring_msg=$(get_i18n_string "configuring_ja_netfilter") printf "\r%s %d/%d %s %d%%" "$configuring_msg" "$current" "$total" "$bar" "$percent" } do_download_resources() { local resources=( "${URL_DOWNLOAD}/ja-netfilter.jar|${file_netfilter_jar}" "${URL_DOWNLOAD}/config/dns.conf|${dir_config}/dns.conf" "${URL_DOWNLOAD}/config/env.conf|${dir_config}/env.conf" "${URL_DOWNLOAD}/config/native.conf|${dir_config}/native.conf" "${URL_DOWNLOAD}/config/power.conf|${dir_config}/power.conf" "${URL_DOWNLOAD}/config/url.conf|${dir_config}/url.conf" "${URL_DOWNLOAD}/plugins/dns.jar|${dir_plugins}/dns.jar" "${URL_DOWNLOAD}/plugins/env.jar|${dir_plugins}/env.jar" "${URL_DOWNLOAD}/plugins/native.jar|${dir_plugins}/native.jar" "${URL_DOWNLOAD}/plugins/power.jar|${dir_plugins}/power.jar" "${URL_DOWNLOAD}/plugins/url.jar|${dir_plugins}/url.jar" "${URL_DOWNLOAD}/plugins/hideme.jar|${dir_plugins}/hideme.jar" "${URL_DOWNLOAD}/plugins/privacy.jar|${dir_plugins}/privacy.jar" ) local total_files=${#resources[@]} local count=0 debug "source_address" debug "source_privacy" debug "suggest_check_sha1" for item in "${resources[@]}"; do IFS='|' read -r url path <<< "$item" download_one_file "$url" "$path" ((count++)) progress_bar "$count" "$total_files" done echo -e "\n" } # ============ 清理并更新 .vmoptions 文件 ============= clean_vmoptions() { local file="$1" if [ ! -f "$file" ]; then debug "cleaning_vm_file_not_exist" "$file" return 0 fi local temp_lines=() local keywords=( "-javaagent" "--add-opens=java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED" "--add-opens=java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED" ) while IFS= read -r line; do local matched=false for keyword in "${keywords[@]}"; do [[ "$line" == *"$keyword"* ]] && matched=true && break done [[ "$matched" == false ]] && temp_lines+=("$line") done < "$file" printf "%s\n" "${temp_lines[@]}" > "$file" debug "cleaning_vm_file" "$file" } append_vmoptions() { local file="$1" if [ ! -f "$file" ]; then touch "$file" || { error "generating_vm_file_failed" "$file" return } fi cat >> "$file" < /dev/null if [ $? -eq 0 ]; then success "activation_success" "$dir_product_name" else warning "manual_activation_required" "$dir_product_name" fi } # ============ 处理单个 Jetbrains 产品 ============= handle_jetbrains_dir() { local dir="$1" local dir_product_name=$(basename "$dir") local obj_product_name="" local obj_product_code="" for ((i = 0; i < $(echo "$PRODUCTS" | jq length); i++)); do IFS='|' read -r name code <<< "$(parse_product_from_json "$i")" local lowercase_dir=$(echo "${dir_product_name}" | tr '[:upper:]' '[:lower:]') if [[ "$lowercase_dir" == *"$name"* ]]; then obj_product_name="$name" obj_product_code="$code" break fi done [ -z "$obj_product_name" ] && return info "processing_product" "$dir_product_name" local file_home="${dir}/.home" [ -f "$file_home" ] || { warning "not_found_home" "$file_home" return } debug "home_path" "$file_home" local install_path=$(cat "$file_home") [ -d "$install_path" ] || { warning "path_not_exist" "$install_path" return } debug "home_content" "$install_path" local dir_bin="${install_path}/bin" [ -d "$dir_bin" ] || { warning "bin_dir_not_exist" "$dir_product_name" return } local dir_config_product="${dir_config_jb}/${dir_product_name}" # 先查找所有 .vmoptions 文件 files=("${dir_config_product}"/*${FILE_VMOPTIONS}) # 判断是否真的找到了文件 if [[ -f "${files[0]}" ]]; then for file_vmoption in "${files[@]}"; do clean_vmoptions "$file_vmoption" append_vmoptions "$file_vmoption" done else debug "vmoptions_not_found_creating" "$dir_product_name" append_vmoptions "${dir_config_product}/${obj_product_name}${FILE_VMOPTIONS}" fi # 判断${dir_config_product}/jetbrains_client.vmoptions是否存在,如果不存在则创建一个默认的 local file_jetbrains_client="${dir_config_product}/jetbrains_client.vmoptions" if [ ! -f "${file_jetbrains_client}" ]; then append_vmoptions "${file_jetbrains_client}" else clean_vmoptions "${file_jetbrains_client}" append_vmoptions "${file_jetbrains_client}" fi generate_license "$obj_product_name" "$obj_product_code" "$dir_product_name" } # ============ 主流程 ============= main() { clear show_ascii_jb info "welcome_msg" warning "script_date" error "warning_msg" warning "close_products" read -r read_license_info info "processing" check_and_install_deps if [ ! -d "${dir_config_jb}" ]; then error "dir_not_found" "${dir_config_jb}" exit 1 fi debug "config_dir" "${dir_config_jb}" do_create_work_dir remove_env_vars do_download_resources for dir in "${dir_cache_jb}"/*; do [ -d "$dir" ] && handle_jetbrains_dir "$dir" done info "processing_completed" sleep 1 } main "$@" # 删除自己 rm -f "${BASH_SOURCE[0]}"