From 16a13b4bef6db04c9e9145bff596b417c194196c Mon Sep 17 00:00:00 2001 From: Arvin <62139570+wnlen@users.noreply.github.com> Date: Sat, 21 Mar 2026 17:37:14 +0800 Subject: [PATCH] Update clashctl --- clashctl | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/clashctl b/clashctl index f464fd5..767cd10 100755 --- a/clashctl +++ b/clashctl @@ -326,6 +326,7 @@ cmd_update() { cmd_update_force() { local branch remote_name + local env_file backup_file if ! has_git_repo; then err "当前目录不是 Git 仓库: $PROJECT_DIR" @@ -339,8 +340,17 @@ cmd_update_force() { fi remote_name="origin" + env_file="$PROJECT_DIR/.env" + backup_file="$PROJECT_DIR/runtime/.env.local.backup" - echo "[WARN] force update: local changes will be discarded" + mkdir -p "$PROJECT_DIR/runtime" + + if [ -f "$env_file" ]; then + echo "[INFO] backing up local env overrides ..." + backup_local_env_overrides "$env_file" "$backup_file" + fi + + echo "[WARN] force update: local code changes will be discarded" git -C "$PROJECT_DIR" fetch "$remote_name" "$branch" || { err "git fetch 失败" exit 1 @@ -351,6 +361,11 @@ cmd_update_force() { exit 1 } + if [ -f "$env_file" ] && [ -f "$backup_file" ]; then + echo "[INFO] restoring local env overrides ..." + restore_local_env_overrides "$env_file" "$backup_file" + fi + echo "[INFO] regenerating config ..." if ! bash "$PROJECT_DIR/scripts/generate_config.sh"; then err "配置生成失败" @@ -364,7 +379,7 @@ cmd_update_force() { exit 1 } else - "$PROJECT_DIR/scripts/run_clash.sh" --daemon || { + bash "$PROJECT_DIR/scripts/run_clash.sh" --daemon || { err "脚本模式启动失败" exit 1 } @@ -927,6 +942,75 @@ cmd_logs() { esac } +read_env_kv() { + local env_file="$1" + local key="$2" + + [ -f "$env_file" ] || return 0 + sed -nE "s/^[[:space:]]*(export[[:space:]]+)?${key}=['\"]?([^'\"]*)['\"]?$/\2/p" "$env_file" | head -n 1 +} + +write_env_kv() { + local env_file="$1" + local key="$2" + local value="$3" + local escaped="${value//\\/\\\\}" + escaped="${escaped//&/\\&}" + escaped="${escaped//|/\\|}" + escaped="${escaped//\'/\'\\\'\'}" + + if grep -qE "^[[:space:]]*(export[[:space:]]+)?${key}=" "$env_file"; then + sed -i -E "s|^[[:space:]]*(export[[:space:]]+)?${key}=.*$|export ${key}='${escaped}'|g" "$env_file" + else + printf "export %s='%s'\n" "$key" "$value" >> "$env_file" + fi +} + +backup_local_env_overrides() { + local env_file="$1" + local backup_file="$2" + + : > "$backup_file" + + local keys=( + CLASH_URL + CLASH_SECRET + CLASH_HTTP_PORT + CLASH_SOCKS_PORT + CLASH_REDIR_PORT + CLASH_LISTEN_IP + CLASH_ALLOW_LAN + EXTERNAL_CONTROLLER_ENABLED + EXTERNAL_CONTROLLER + ALLOW_INSECURE_TLS + CLASH_AUTO_UPDATE + CLASH_DOWNLOAD_URL_TEMPLATE + ) + + local key value + for key in "${keys[@]}"; do + value="$(read_env_kv "$env_file" "$key")" + if [ -n "${value:-}" ]; then + printf "%s=%s\n" "$key" "$value" >> "$backup_file" + fi + done +} + +restore_local_env_overrides() { + local env_file="$1" + local backup_file="$2" + + [ -f "$backup_file" ] || return 0 + + local line key value + while IFS= read -r line; do + [ -n "$line" ] || continue + key="${line%%=*}" + value="${line#*=}" + write_env_kv "$env_file" "$key" "$value" + done < "$backup_file" +} + main() { local from_systemd="false"