mirror of
https://github.com/wnlen/clash-for-linux.git
synced 2026-10-10 20:23:04 +08:00
translate into Chinese
This commit is contained in:
@@ -38,7 +38,7 @@ resolve_project_dir() {
|
||||
fi
|
||||
done
|
||||
|
||||
echo "[ERROR] Unable to locate project directory" >&2
|
||||
echo "[ERROR] 无法定位项目目录" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -62,10 +62,10 @@ err() { log "\033[31m[ERROR]\033[0m $*"; }
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
clashctl COMMAND [OPTIONS]
|
||||
用法:
|
||||
clashctl 命令 [选项]
|
||||
|
||||
Commands:
|
||||
指令:
|
||||
on 开启当前终端代理
|
||||
off 关闭当前终端代理
|
||||
start 启动 Clash
|
||||
@@ -82,10 +82,10 @@ Commands:
|
||||
tun status|on|off 查看/启用/关闭 Tun
|
||||
mixin status|on|off 查看/启用/关闭 Mixin
|
||||
|
||||
Advanced Commands:
|
||||
高级命令:
|
||||
generate 生成配置(调试用,不会启动服务)
|
||||
|
||||
Options:
|
||||
选项:
|
||||
--from-systemd 内部使用,避免 stop 递归调用 systemctl
|
||||
-h, --help 显示帮助信息
|
||||
EOF
|
||||
@@ -132,7 +132,7 @@ write_env_bool() {
|
||||
if grep -qE "^[[:space:]]*(export[[:space:]]+)?${key}=" "$ENV_FILE"; then
|
||||
sed -i -E "s|^[[:space:]]*(export[[:space:]]+)?${key}=.*$|export ${key}=\"${value}\"|g" "$ENV_FILE"
|
||||
else
|
||||
echo "export ${key}=\"${value}\"" >> "$ENV_FILE"
|
||||
echo "已写入环境变量 ${key}=\"${value}\"" >> "$ENV_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -240,11 +240,11 @@ cmd_start() {
|
||||
case "$mode" in
|
||||
systemd|systemd-installed)
|
||||
start_via_systemd
|
||||
ok "Clash started via systemd"
|
||||
ok "已通过 systemd 启动 Clash"
|
||||
;;
|
||||
script|none)
|
||||
start_via_script
|
||||
ok "Clash started via script mode"
|
||||
ok "已通过脚本模式启动 Clash"
|
||||
;;
|
||||
*)
|
||||
err "未知模式: $mode"
|
||||
@@ -261,21 +261,21 @@ cmd_stop() {
|
||||
case "$mode" in
|
||||
systemd)
|
||||
if [ "$from_systemd" = "true" ]; then
|
||||
ok "Stop requested from systemd, skip recursive systemctl stop"
|
||||
ok "来自 systemd 的停止请求,已跳过重复停止操作"
|
||||
return 0
|
||||
fi
|
||||
stop_via_systemd
|
||||
ok "Clash stopped via systemd"
|
||||
ok "已通过 systemd 停止 Clash"
|
||||
;;
|
||||
systemd-installed)
|
||||
info "systemd service installed but not running"
|
||||
info "systemd 服务已安装但未运行"
|
||||
;;
|
||||
script)
|
||||
stop_via_script
|
||||
ok "Clash stopped via script mode"
|
||||
ok "已通过脚本模式停止 Clash"
|
||||
;;
|
||||
none)
|
||||
info "Clash is not running"
|
||||
info "Clash 未运行"
|
||||
;;
|
||||
*)
|
||||
err "未知模式: $mode"
|
||||
@@ -312,7 +312,7 @@ cmd_update() {
|
||||
fi
|
||||
|
||||
if [ "$pull_ok" -eq 1 ]; then
|
||||
echo "[INFO] pulling latest code from ${remote_name}/${branch} ..."
|
||||
echo "[INFO] 正在从 ${remote_name}/${branch} 拉取最新代码 ..."
|
||||
if ! git -C "$PROJECT_DIR" pull --ff-only "$remote_name" "$branch"; then
|
||||
echo "[WARN] git pull 失败,自动切换到强制更新模式"
|
||||
pull_ok=0
|
||||
@@ -320,13 +320,13 @@ cmd_update() {
|
||||
fi
|
||||
|
||||
if [ "$pull_ok" -eq 0 ]; then
|
||||
echo "[INFO] fetching latest code from ${remote_name}/${branch} ..."
|
||||
echo "[INFO] 正在获取 ${remote_name}/${branch} 最新代码 ..."
|
||||
if ! git -C "$PROJECT_DIR" fetch "$remote_name" "$branch"; then
|
||||
err "git fetch 失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[WARN] resetting local code to ${remote_name}/${branch}"
|
||||
echo "[WARN] 正在重置本地代码到 ${remote_name}/${branch}"
|
||||
if ! git -C "$PROJECT_DIR" reset --hard "${remote_name}/${branch}"; then
|
||||
err "git reset --hard 失败"
|
||||
exit 1
|
||||
@@ -339,32 +339,32 @@ cmd_update() {
|
||||
fi
|
||||
|
||||
# 修复脚本权限,避免 203/EXEC
|
||||
echo "[INFO] fixing executable permissions ..."
|
||||
echo "[INFO] 修复执行权限中..."
|
||||
chmod +x "$PROJECT_DIR"/scripts/*.sh 2>/dev/null || true
|
||||
chmod +x "$PROJECT_DIR"/bin/* 2>/dev/null || true
|
||||
sed -i 's/\r$//' "$PROJECT_DIR"/scripts/*.sh 2>/dev/null || true
|
||||
|
||||
# 先停服务,避免 generate 时误判端口占用导致漂移
|
||||
echo "[INFO] stopping service before regenerate ..."
|
||||
echo "[INFO] 停止服务(准备重新生成配置)..."
|
||||
if has_systemd; then
|
||||
systemctl stop clash-for-linux.service 2>/dev/null || true
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
echo "[INFO] regenerating config ..."
|
||||
echo "[INFO] 生成配置中..."
|
||||
if ! bash "$PROJECT_DIR/scripts/generate_config.sh"; then
|
||||
err "配置生成失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[INFO] starting service ..."
|
||||
echo "[INFO] 启动服务中..."
|
||||
if has_systemd; then
|
||||
if ! systemctl start clash-for-linux.service; then
|
||||
err "systemd 启动失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[INFO] waiting for service to be active ..."
|
||||
echo "[INFO] 等待服务就绪..."
|
||||
if wait_for_systemd_active; then
|
||||
ok "更新完成"
|
||||
cmd_status
|
||||
@@ -407,11 +407,11 @@ cmd_update_force() {
|
||||
mkdir -p "$PROJECT_DIR/runtime"
|
||||
|
||||
if [ -f "$env_file" ]; then
|
||||
echo "[INFO] backing up local env overrides ..."
|
||||
echo "[INFO] 正在备份本地环境变量覆盖项 ..."
|
||||
backup_local_env_overrides "$env_file" "$backup_file"
|
||||
fi
|
||||
|
||||
echo "[WARN] force update: local code changes will be discarded"
|
||||
echo "[WARN] 强制更新:本地代码修改将被覆盖"
|
||||
git -C "$PROJECT_DIR" fetch "$remote_name" "$branch" || {
|
||||
err "git fetch 失败"
|
||||
exit 1
|
||||
@@ -423,17 +423,17 @@ cmd_update_force() {
|
||||
}
|
||||
|
||||
if [ -f "$env_file" ] && [ -f "$backup_file" ]; then
|
||||
echo "[INFO] restoring local env overrides ..."
|
||||
echo "[INFO] 正在恢复本地环境变量 ..."
|
||||
restore_local_env_overrides "$env_file" "$backup_file"
|
||||
fi
|
||||
|
||||
echo "[INFO] regenerating config ..."
|
||||
echo "[INFO] 正在重新生成配置 ..."
|
||||
if ! bash "$PROJECT_DIR/scripts/generate_config.sh"; then
|
||||
err "配置生成失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[INFO] restarting service ..."
|
||||
echo "[INFO] 正在重启服务 ..."
|
||||
if has_systemd; then
|
||||
systemctl restart clash-for-linux.service || {
|
||||
err "systemd 重启失败"
|
||||
@@ -523,29 +523,29 @@ wait_for_systemd_active() {
|
||||
}
|
||||
|
||||
cmd_restart() {
|
||||
echo "[INFO] stopping Clash ..."
|
||||
echo "[INFO] 正在停止 Clash ..."
|
||||
cmd_stop "${1:-false}" || true
|
||||
sleep 1
|
||||
|
||||
echo "[INFO] regenerating config ..."
|
||||
echo "[INFO] 正在重新生成配置 ..."
|
||||
if ! cmd_generate; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "[INFO] starting Clash ..."
|
||||
echo "[INFO] 正在启动 Clash ..."
|
||||
if ! cmd_start; then
|
||||
err "启动失败"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if has_systemd; then
|
||||
echo "[INFO] waiting for service to be active ..."
|
||||
echo "[INFO] 正在等待服务启动完成 ..."
|
||||
if wait_for_systemd_active; then
|
||||
ok "重启完成"
|
||||
return 0
|
||||
fi
|
||||
|
||||
err "服务启动未就绪"
|
||||
err "服务未就绪"
|
||||
systemctl status "$SERVICE_NAME" -l --no-pager || true
|
||||
return 1
|
||||
fi
|
||||
@@ -589,14 +589,14 @@ cmd_secret() {
|
||||
local secret
|
||||
|
||||
if [ ! -s "$RUNTIME_CONFIG" ]; then
|
||||
err "runtime config not found: $RUNTIME_CONFIG"
|
||||
echo "Please run install.sh or clashctl generate" >&2
|
||||
err "未找到运行时配置文件: $RUNTIME_CONFIG"
|
||||
echo "请先执行 install.sh 或 clashctl generate" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
secret="$(read_runtime_config_value "secret" || true)"
|
||||
if [ -z "${secret:-}" ]; then
|
||||
err "secret not found in $RUNTIME_CONFIG"
|
||||
err "未找到 secret 在配置: $RUNTIME_CONFIG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -746,77 +746,77 @@ cmd_status() {
|
||||
secret_exists="yes"
|
||||
fi
|
||||
|
||||
echo "=== Clash Status ==="
|
||||
echo "Project : $PROJECT_DIR"
|
||||
echo "Mode : $mode"
|
||||
echo "Running : $running"
|
||||
echo "Config : $RUNTIME_CONFIG"
|
||||
echo "=== Clash 状态 ==="
|
||||
echo "项目路径 : $PROJECT_DIR"
|
||||
echo "运行模式 : $mode"
|
||||
echo "运行状态 : $running"
|
||||
echo "配置文件 : $RUNTIME_CONFIG"
|
||||
|
||||
if [ -f "$RUNTIME_CONFIG" ]; then
|
||||
echo "ConfigExists : yes"
|
||||
echo "配置存在 : 是"
|
||||
else
|
||||
echo "ConfigExists : no"
|
||||
echo "配置存在 : 否"
|
||||
fi
|
||||
|
||||
if [ -f "$STATE_FILE" ]; then
|
||||
echo "StateFile : $STATE_FILE"
|
||||
echo "状态文件 : $STATE_FILE"
|
||||
else
|
||||
echo "StateFile : missing"
|
||||
echo "状态文件 : 缺失"
|
||||
fi
|
||||
|
||||
case "$mode" in
|
||||
systemd|systemd-installed)
|
||||
echo "Service : installed"
|
||||
echo "Active : ${service_active:-unknown}"
|
||||
echo "Enabled : ${service_enabled:-unknown}"
|
||||
echo "服务类型 : systemd"
|
||||
echo "服务状态 : ${service_active:-未知}"
|
||||
echo "开机自启 : ${service_enabled:-未知}"
|
||||
;;
|
||||
script)
|
||||
echo "Service : script"
|
||||
echo "PID : ${pid:-unknown}"
|
||||
echo "服务类型 : 脚本模式"
|
||||
echo "进程 ID : ${pid:-未知}"
|
||||
;;
|
||||
none)
|
||||
echo "Service : none"
|
||||
echo "服务类型 : 未安装"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Generate : ${generate_status:-unknown}"
|
||||
echo "配置生成状态 : ${generate_status:-未知}"
|
||||
if [ -n "${generate_reason:-}" ]; then
|
||||
echo "GenReason : $generate_reason"
|
||||
echo "生成失败原因 : $generate_reason"
|
||||
fi
|
||||
if [ -n "${config_source:-}" ]; then
|
||||
echo "ConfigSource : $config_source"
|
||||
echo "配置来源 : $config_source"
|
||||
fi
|
||||
if [ -n "${generate_at:-}" ]; then
|
||||
echo "GeneratedAt : $generate_at"
|
||||
echo "生成时间 : $generate_at"
|
||||
fi
|
||||
|
||||
if [ -n "${run_status:-}" ]; then
|
||||
echo "RunStatus : $run_status"
|
||||
echo "运行结果 : $run_status"
|
||||
fi
|
||||
if [ -n "${run_mode:-}" ]; then
|
||||
echo "RunMode : $run_mode"
|
||||
echo "运行方式 : $run_mode"
|
||||
fi
|
||||
if [ -n "${run_pid:-}" ]; then
|
||||
echo "RunPID : $run_pid"
|
||||
echo "运行进程 : $run_pid"
|
||||
fi
|
||||
if [ -n "${run_at:-}" ]; then
|
||||
echo "RunAt : $run_at"
|
||||
echo "启动时间 : $run_at"
|
||||
fi
|
||||
|
||||
echo "ProxyPort : ${http_port:-unknown}"
|
||||
echo "DashPort : ${dashboard_port:-unknown}"
|
||||
echo "代理端口 : ${http_port:-未知}"
|
||||
echo "面板端口 : ${dashboard_port:-未知}"
|
||||
|
||||
if [ -n "${controller:-}" ]; then
|
||||
echo "Controller : $controller"
|
||||
echo "控制地址 : $controller"
|
||||
else
|
||||
echo "Controller : unknown"
|
||||
echo "控制地址 : 未知"
|
||||
fi
|
||||
|
||||
if [ -n "${dashboard_url:-}" ]; then
|
||||
echo "Dashboard : $dashboard_url"
|
||||
echo "面板地址 : $dashboard_url"
|
||||
fi
|
||||
|
||||
echo "Secret : $secret_exists"
|
||||
echo "密钥状态 : $secret_exists"
|
||||
}
|
||||
|
||||
doctor_ok() {
|
||||
@@ -843,30 +843,30 @@ cmd_doctor() {
|
||||
|
||||
mode="$(detect_mode)"
|
||||
|
||||
echo "=== Clash Doctor ==="
|
||||
echo "Project : $PROJECT_DIR"
|
||||
echo "Mode : $mode"
|
||||
echo "Config : $RUNTIME_CONFIG"
|
||||
echo "=== Clash 健康检查 ==="
|
||||
echo "项目路径 : $PROJECT_DIR"
|
||||
echo "运行模式 : $mode"
|
||||
echo "配置文件 : $RUNTIME_CONFIG"
|
||||
echo
|
||||
|
||||
if [ -s "$RUNTIME_CONFIG" ]; then
|
||||
doctor_ok "runtime config exists: $RUNTIME_CONFIG"
|
||||
doctor_ok "运行配置文件存在: $RUNTIME_CONFIG"
|
||||
else
|
||||
doctor_err "runtime config missing or empty: $RUNTIME_CONFIG"
|
||||
doctor_err "运行配置文件不存在或为空: $RUNTIME_CONFIG"
|
||||
failed=1
|
||||
fi
|
||||
|
||||
if [ -f "$RUNTIME_CONFIG" ]; then
|
||||
if grep -q '\${' "$RUNTIME_CONFIG"; then
|
||||
doctor_err "runtime config contains unresolved placeholders"
|
||||
doctor_err "配置文件存在未替换变量"
|
||||
failed=1
|
||||
else
|
||||
doctor_ok "runtime config has no unresolved placeholders"
|
||||
doctor_ok "配置文件检查通过(无未替换变量)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f "$STATE_FILE" ]; then
|
||||
doctor_ok "state file exists: $STATE_FILE"
|
||||
doctor_ok "状态文件存在: $STATE_FILE"
|
||||
|
||||
last_generate_status="$(read_state_value LAST_GENERATE_STATUS || true)"
|
||||
last_generate_reason="$(read_state_value LAST_GENERATE_REASON || true)"
|
||||
@@ -874,21 +874,21 @@ cmd_doctor() {
|
||||
|
||||
if [ -n "${last_generate_status:-}" ]; then
|
||||
if [ "$last_generate_status" = "success" ]; then
|
||||
doctor_ok "last generate status: success (${last_generate_reason:-unknown})"
|
||||
doctor_ok "最近配置生成状态:成功 (${last_generate_reason:-未知})"
|
||||
else
|
||||
doctor_warn "last generate status: ${last_generate_status:-unknown} (${last_generate_reason:-unknown})"
|
||||
doctor_warn "最近配置生成状态:${last_generate_status:-未知} (${last_generate_reason:-未知})"
|
||||
warned=1
|
||||
fi
|
||||
else
|
||||
doctor_warn "state file exists but LAST_GENERATE_STATUS is empty"
|
||||
doctor_warn "状态文件存在,但 LAST_GENERATE_STATUS 为空"
|
||||
warned=1
|
||||
fi
|
||||
|
||||
if [ -n "${last_config_source:-}" ]; then
|
||||
doctor_ok "config source: $last_config_source"
|
||||
doctor_ok "配置来源: $last_config_source"
|
||||
fi
|
||||
else
|
||||
doctor_warn "state file missing: $STATE_FILE"
|
||||
doctor_warn "状态文件缺失: $STATE_FILE"
|
||||
warned=1
|
||||
fi
|
||||
|
||||
@@ -896,31 +896,31 @@ cmd_doctor() {
|
||||
systemd)
|
||||
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
||||
running="yes"
|
||||
doctor_ok "systemd service is active"
|
||||
doctor_ok "systemd 服务运行正常"
|
||||
else
|
||||
doctor_err "systemd service is installed but not active"
|
||||
doctor_err "systemd 服务已安装但未运行"
|
||||
failed=1
|
||||
fi
|
||||
;;
|
||||
script)
|
||||
if is_script_running; then
|
||||
running="yes"
|
||||
doctor_ok "script mode process is running (pid=$(read_pid 2>/dev/null || echo unknown))"
|
||||
doctor_ok "脚本模式进程正在运行 (pid=$(read_pid 2>/dev/null || echo 未知))"
|
||||
else
|
||||
doctor_err "script mode detected but PID is not running"
|
||||
doctor_err "已检测到脚本模式,但进程未运行"
|
||||
failed=1
|
||||
fi
|
||||
;;
|
||||
systemd-installed)
|
||||
doctor_warn "systemd unit exists but service is not running"
|
||||
doctor_warn "systemd 单元已存在,但服务未运行"
|
||||
warned=1
|
||||
;;
|
||||
none)
|
||||
doctor_warn "no running instance detected"
|
||||
doctor_warn "未检测到运行中的实例"
|
||||
warned=1
|
||||
;;
|
||||
*)
|
||||
doctor_err "unknown mode: $mode"
|
||||
doctor_err "未知运行模式: $mode"
|
||||
failed=1
|
||||
;;
|
||||
esac
|
||||
@@ -930,51 +930,51 @@ cmd_doctor() {
|
||||
dashboard_port="$(port_from_controller)"
|
||||
|
||||
if [ -n "${controller:-}" ]; then
|
||||
doctor_ok "external-controller configured: $controller"
|
||||
doctor_ok "控制地址已配置: $controller"
|
||||
else
|
||||
doctor_warn "external-controller not found in runtime config, fallback assumed: 127.0.0.1:9090"
|
||||
doctor_warn "未配置 external-controller,使用默认值: 127.0.0.1:9090"
|
||||
warned=1
|
||||
fi
|
||||
|
||||
if [ -n "${dashboard_url:-}" ]; then
|
||||
doctor_ok "dashboard url: $dashboard_url"
|
||||
doctor_ok "面板地址: $dashboard_url"
|
||||
else
|
||||
doctor_warn "dashboard url could not be derived"
|
||||
doctor_warn "无法获取面板地址"
|
||||
warned=1
|
||||
fi
|
||||
|
||||
http_port="$(http_port_from_config)"
|
||||
if check_port_listening "$http_port"; then
|
||||
doctor_ok "proxy port is listening: $http_port"
|
||||
doctor_ok "代理端口正常监听: $http_port"
|
||||
else
|
||||
rc=$?
|
||||
if [ "$rc" -eq 2 ]; then
|
||||
doctor_warn "cannot verify proxy port (ss/netstat not available)"
|
||||
doctor_warn "无法检测代理端口(缺少 ss/netstat 工具)"
|
||||
warned=1
|
||||
else
|
||||
if [ "$running" = "yes" ]; then
|
||||
doctor_err "proxy port is not listening: $http_port"
|
||||
doctor_err "代理端口未监听: $http_port"
|
||||
failed=1
|
||||
else
|
||||
doctor_warn "proxy port is not listening: $http_port"
|
||||
doctor_warn "代理端口未监听: $http_port"
|
||||
warned=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if check_port_listening "$dashboard_port"; then
|
||||
doctor_ok "dashboard port is listening: $dashboard_port"
|
||||
doctor_ok "面板端口正常监听: $dashboard_port"
|
||||
else
|
||||
rc=$?
|
||||
if [ "$rc" -eq 2 ]; then
|
||||
doctor_warn "cannot verify dashboard port (ss/netstat not available)"
|
||||
doctor_warn "无法检测面板端口(缺少 ss/netstat 工具)"
|
||||
warned=1
|
||||
else
|
||||
if [ "$running" = "yes" ]; then
|
||||
doctor_err "dashboard port is not listening: $dashboard_port"
|
||||
doctor_err "面板端口未监听: $dashboard_port"
|
||||
failed=1
|
||||
else
|
||||
doctor_warn "dashboard port is not listening: $dashboard_port"
|
||||
doctor_warn "面板端口未监听: $dashboard_port"
|
||||
warned=1
|
||||
fi
|
||||
fi
|
||||
@@ -982,14 +982,14 @@ cmd_doctor() {
|
||||
|
||||
if [ -n "${dashboard_url:-}" ]; then
|
||||
if check_dashboard_http "$dashboard_url"; then
|
||||
doctor_ok "dashboard http reachable"
|
||||
doctor_ok "面板访问正常"
|
||||
else
|
||||
rc=$?
|
||||
if [ "$rc" -eq 2 ]; then
|
||||
doctor_warn "cannot verify dashboard http (curl/wget not available)"
|
||||
doctor_warn "无法检测面板 HTTP(缺少 curl/wget 工具)"
|
||||
warned=1
|
||||
else
|
||||
doctor_warn "dashboard http not reachable: $dashboard_url"
|
||||
doctor_warn "面板无法访问: $dashboard_url"
|
||||
warned=1
|
||||
fi
|
||||
fi
|
||||
@@ -997,38 +997,38 @@ cmd_doctor() {
|
||||
|
||||
secret="$(read_runtime_config_value "secret" || true)"
|
||||
if [ -n "${secret:-}" ]; then
|
||||
doctor_ok "secret exists in runtime config"
|
||||
doctor_ok "已配置 secret"
|
||||
else
|
||||
doctor_warn "secret missing in runtime config"
|
||||
doctor_warn "未配置 secret"
|
||||
warned=1
|
||||
fi
|
||||
|
||||
if command_exists clashctl; then
|
||||
doctor_ok "clashctl command available: $(command -v clashctl)"
|
||||
doctor_ok "clashctl 命令可用: $(command -v clashctl)"
|
||||
else
|
||||
doctor_warn "clashctl command not found in PATH"
|
||||
doctor_warn "未在 PATH 中找到 clashctl 命令"
|
||||
warned=1
|
||||
fi
|
||||
|
||||
if [ -f "$PROFILED_FILE" ]; then
|
||||
doctor_ok "shell proxy helper exists: $PROFILED_FILE"
|
||||
doctor_ok "Shell 代理辅助脚本存在: $PROFILED_FILE"
|
||||
else
|
||||
doctor_warn "shell proxy helper missing: $PROFILED_FILE"
|
||||
doctor_warn "Shell 代理辅助脚本缺失: $PROFILED_FILE"
|
||||
warned=1
|
||||
fi
|
||||
|
||||
echo
|
||||
if [ "$failed" -ne 0 ]; then
|
||||
doctor_err "doctor result: FAILED"
|
||||
doctor_err "检查结果:失败"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$warned" -ne 0 ]; then
|
||||
doctor_warn "doctor result: WARN"
|
||||
doctor_warn "检查结果:警告"
|
||||
return 0
|
||||
fi
|
||||
|
||||
doctor_ok "doctor result: HEALTHY"
|
||||
doctor_ok "检查结果:健康"
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
set -euo pipefail
|
||||
|
||||
# 作用:
|
||||
# - 将订阅内容转换成 Clash Meta / Mihomo 可用的完整 YAML 配置
|
||||
# - 默认使用 subconverter HTTP /sub 接口(最稳:用 -G + --data-urlencode)
|
||||
# - 失败则跳过,不影响主流程
|
||||
# - 将订阅内容转换为 Clash Meta / Mihomo 可用的完整 YAML 配置
|
||||
# - 默认使用 subconverter HTTP /sub 接口(最稳:使用 -G + --data-urlencode)
|
||||
# - 转换失败则跳过,不影响主流程
|
||||
#
|
||||
# 输入/输出约定:
|
||||
# - IN_FILE:原订阅(默认 temp/clash.yaml)
|
||||
# 输入 / 输出约定:
|
||||
# - IN_FILE:原始订阅(默认 temp/clash.yaml)
|
||||
# - OUT_FILE:转换后的配置(默认 temp/clash_config.yaml)
|
||||
#
|
||||
# 设计原则:
|
||||
# - 绝不 exit 1(失败只 warn 并 exit 0)
|
||||
# - 已是完整 Clash 配置则直接 copy
|
||||
# - 没有 CLASH_URL(原始订阅 URL)则不转换(subconverter 最稳是 url=...)
|
||||
# - 绝不 exit 1(失败只输出 warn 并 exit 0)
|
||||
# - 如果本身已是完整 Clash 配置,则直接复制
|
||||
# - 如果没有 CLASH_URL(原始订阅 URL),则不执行转换(subconverter 最稳妥的方式是 url=...)
|
||||
|
||||
Server_Dir="${Server_Dir:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
||||
Temp_Dir="${Temp_Dir:-$Server_Dir/temp}"
|
||||
@@ -23,38 +23,38 @@ mkdir -p "$Temp_Dir"
|
||||
IN_FILE="${IN_FILE:-$Temp_Dir/clash.yaml}"
|
||||
OUT_FILE="${OUT_FILE:-$Temp_Dir/clash_config.yaml}"
|
||||
|
||||
# “更先进”的默认:Clash Meta / Mihomo
|
||||
SUB_TARGET="${SUB_TARGET:-clashmeta}" # 推荐 clashmeta(兼容面最广)
|
||||
SUB_URL="${CLASH_URL:-}" # 原始订阅 URL(.env 里 export CLASH_URL=...)
|
||||
# 更推荐的默认目标:Clash Meta / Mihomo
|
||||
SUB_TARGET="${SUB_TARGET:-clashmeta}" # 推荐 clashmeta(兼容性最好)
|
||||
SUB_URL="${CLASH_URL:-}" # 原始订阅 URL(.env 中 export CLASH_URL=...)
|
||||
|
||||
# 0) 输入不存在就跳过
|
||||
# 0) 输入文件不存在则跳过
|
||||
if [ ! -s "$IN_FILE" ]; then
|
||||
echo "[WARN] no input file: $IN_FILE"
|
||||
echo "[WARN] 未找到输入文件: $IN_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 1) 如果看起来已经是完整 Clash 配置,就直接用,不转换
|
||||
# (包含 proxies / proxy-providers / rules / port 等任一关键词即可认为是完整配置)
|
||||
# 1) 如果看起来已经是完整 Clash 配置,则直接使用,不再转换
|
||||
# (包含 proxies / proxy-providers / rules / port 等任一关键字即可视为完整配置)
|
||||
if grep -qE '^(proxies:|proxy-providers:|mixed-port:|port:|rules:|dns:)' "$IN_FILE"; then
|
||||
cp -f "$IN_FILE" "$OUT_FILE"
|
||||
echo "[OK] input already looks like a Clash config -> $OUT_FILE"
|
||||
echo "[OK] 输入内容已是 Clash 配置,直接使用 -> $OUT_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 2) subconverter 不可用就跳过
|
||||
# 2) subconverter 不可用则跳过
|
||||
if [ "${SUBCONVERTER_READY:-false}" != "true" ] || [ -z "${SUBCONVERTER_URL:-}" ]; then
|
||||
echo "[WARN] subconverter not ready, skip conversion"
|
||||
echo "[WARN] subconverter 未就绪,跳过转换"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 3) 没有原始 URL 就不转(subconverter 最稳是 url=... 拉取)
|
||||
# 3) 没有原始 URL 则不转换(subconverter 最稳妥的方式是 url=... 拉取)
|
||||
if [ -z "${SUB_URL:-}" ]; then
|
||||
echo "[WARN] CLASH_URL empty, cannot convert via /sub, skip"
|
||||
echo "[WARN] CLASH_URL 为空,无法通过 /sub 转换,已跳过"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 4) 调用 subconverter:用 -G + --data-urlencode,避免 url 参数里含 ? & 导致 400
|
||||
# 注意:SUB_URL 必须是原始订阅 URL(例如 https://.../subscribe?token=xxx)
|
||||
# 4) 调用 subconverter:使用 -G + --data-urlencode,避免 url 参数中包含 ? 和 & 导致 400
|
||||
# 注意:SUB_URL 必须为原始订阅 URL(例如 https://.../subscribe?token=xxx)
|
||||
TMP_OUT="${OUT_FILE}.tmp"
|
||||
rm -f "$TMP_OUT" 2>/dev/null || true
|
||||
|
||||
@@ -67,12 +67,12 @@ rc=$?
|
||||
set -e
|
||||
|
||||
if [ "$rc" -ne 0 ] || [ ! -s "$TMP_OUT" ]; then
|
||||
echo "[WARN] convert failed (rc=${rc}), skip"
|
||||
echo "[WARN] 转换失败(rc=${rc}),已跳过"
|
||||
rm -f "$TMP_OUT" 2>/dev/null || true
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mv -f "$TMP_OUT" "$OUT_FILE"
|
||||
echo "[OK] converted via subconverter -> ${OUT_FILE} (target=${SUB_TARGET})"
|
||||
echo "[OK] 已通过 subconverter 完成转换 -> ${OUT_FILE} (target=${SUB_TARGET})"
|
||||
|
||||
true
|
||||
@@ -52,10 +52,10 @@ write_state() {
|
||||
local source="${3:-unknown}"
|
||||
|
||||
cat > "$STATE_FILE" <<EOF
|
||||
LAST_GENERATE_STATUS=$status
|
||||
LAST_GENERATE_REASON=$reason
|
||||
LAST_CONFIG_SOURCE=$source
|
||||
LAST_GENERATE_AT=$(date -Iseconds)
|
||||
LAST_GENERATE_STATUS=$status
|
||||
LAST_GENERATE_REASON=$reason
|
||||
LAST_CONFIG_SOURCE=$source
|
||||
LAST_GENERATE_AT=$(date -Iseconds)
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ apply_controller_to_config() {
|
||||
upsert_yaml_kv_local "$file" "external-controller" "$EXTERNAL_CONTROLLER"
|
||||
|
||||
if [ ! -f "$ui_src/index.html" ]; then
|
||||
echo "[ERROR] UI not found: $ui_src/index.html" >&2
|
||||
echo "[ERROR] UI 未找到: $ui_src/index.html" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -208,19 +208,19 @@ main() {
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "[ERROR] auto update disabled and runtime config missing: $RUNTIME_CONFIG" >&2
|
||||
echo "[错误] 已关闭自动更新,且运行配置缺失: $RUNTIME_CONFIG" >&2
|
||||
write_state "failed" "runtime_missing" "none"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${CLASH_URL:-}" ]; then
|
||||
echo "[ERROR] CLASH_URL is empty" >&2
|
||||
echo "[错误] 未设置 CLASH_URL" >&2
|
||||
write_state "failed" "url_missing" "none"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! download_subscription; then
|
||||
echo "[ERROR] failed to download subscription" >&2
|
||||
echo "[错误] 下载订阅失败" >&2
|
||||
write_state "failed" "download_failed" "none"
|
||||
exit 1
|
||||
fi
|
||||
@@ -237,7 +237,7 @@ main() {
|
||||
fi
|
||||
|
||||
if [ ! -s "$template_file" ]; then
|
||||
echo "[ERROR] missing template config file: $template_file" >&2
|
||||
echo "[错误] 缺少模板配置文件: $template_file" >&2
|
||||
write_state "failed" "missing_template" "none"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -13,7 +13,7 @@ LOG_DIR="$PROJECT_DIR/logs"
|
||||
CONFIG_DIR="$PROJECT_DIR/config"
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "[ERROR] root required to install systemd unit" >&2
|
||||
echo "[ERROR] 安装 systemd 服务需要 root 权限" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
+29
-29
@@ -25,7 +25,7 @@ is_port_in_use() {
|
||||
fi
|
||||
|
||||
if [ "$PORT_CHECK_WARNED" -eq 0 ]; then
|
||||
echo "[WARN] no port check tool found (ss/netstat/lsof)" >&2
|
||||
echo "[WARN] 未检测到端口检查工具(ss/netstat/lsof)" >&2
|
||||
PORT_CHECK_WARNED=1
|
||||
fi
|
||||
|
||||
@@ -66,38 +66,38 @@ find_available_port() {
|
||||
# 解析端口值(核心函数)
|
||||
# =========================
|
||||
resolve_port_value() {
|
||||
local name="$1"
|
||||
local value="$2"
|
||||
local resolved
|
||||
local name="$1"
|
||||
local value="$2"
|
||||
local resolved
|
||||
|
||||
# auto / 空
|
||||
if [ -z "$value" ] || [ "$value" = "auto" ]; then
|
||||
resolved=$(find_available_port) || {
|
||||
echo "[ERROR] ${name} failed to allocate port" >&2
|
||||
return 1
|
||||
}
|
||||
echo "[WARN] ${name} auto assigned: ${resolved}" >&2
|
||||
echo "$resolved"
|
||||
return 0
|
||||
fi
|
||||
# auto / 空
|
||||
if [ -z "$value" ] || [ "$value" = "auto" ]; then
|
||||
resolved=$(find_available_port) || {
|
||||
echo "[ERROR] ${name} 端口分配失败" >&2
|
||||
return 1
|
||||
}
|
||||
echo "[WARN] ${name} 自动分配端口: ${resolved}" >&2
|
||||
echo "$resolved"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 非数字
|
||||
if ! [[ "$value" =~ ^[0-9]+$ ]]; then
|
||||
echo "[ERROR] invalid port: $value" >&2
|
||||
return 1
|
||||
fi
|
||||
# 非数字
|
||||
if ! [[ "$value" =~ ^[0-9]+$ ]]; then
|
||||
echo "[ERROR] 非法端口: $value" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 被占用 → 自动替换
|
||||
if is_port_in_use "$value"; then
|
||||
resolved=$(find_available_port)
|
||||
if [ -n "$resolved" ]; then
|
||||
echo "[WARN] ${name} port ${value} in use, switched to ${resolved}" >&2
|
||||
echo "$resolved"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
# 被占用 → 自动替换
|
||||
if is_port_in_use "$value"; then
|
||||
resolved=$(find_available_port)
|
||||
if [ -n "$resolved" ]; then
|
||||
echo "[WARN] ${name} 端口 ${value} 已被占用,已切换为 ${resolved}" >&2
|
||||
echo "$resolved"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$value"
|
||||
echo "$value"
|
||||
}
|
||||
|
||||
# =========================
|
||||
|
||||
@@ -3,13 +3,13 @@ set -euo pipefail
|
||||
|
||||
# 作用:
|
||||
# - 根据 OS/ARCH 选择 tools/subconverter/<platform>/subconverter
|
||||
# - 生成稳定入口 tools/subconverter/subconverter(软链优先,失败则复制)
|
||||
# -(可选)以 daemon 模式启动本地 subconverter(HTTP 服务)
|
||||
# - 导出统一变量给后续脚本使用:
|
||||
# - 生成稳定入口 tools/subconverter/subconverter(优先软链接,失败则复制)
|
||||
# -(可选)以守护进程模式启动本地 subconverter(HTTP 服务)
|
||||
# - 导出统一变量供后续脚本使用:
|
||||
# SUBCONVERTER_BIN / SUBCONVERTER_READY / SUBCONVERTER_URL
|
||||
#
|
||||
# 设计原则:
|
||||
# - 永不 exit 1(不可用就 Ready=false,主流程继续)
|
||||
# - 永不 exit 1(不可用时标记 Ready=false,主流程继续)
|
||||
# - 不阻塞 start.sh(快速启动,不等待健康检查)
|
||||
|
||||
Server_Dir="${Server_Dir:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
||||
@@ -18,24 +18,24 @@ Temp_Dir="${Temp_Dir:-$Server_Dir/temp}"
|
||||
mkdir -p "$Temp_Dir"
|
||||
|
||||
SC_DIR="$Server_Dir/tools/subconverter"
|
||||
SC_LINK="$SC_DIR/subconverter" # 稳定入口(最终用于启动/调用)
|
||||
SC_LINK="$SC_DIR/subconverter" # 稳定入口(统一调用路径)
|
||||
Subconverter_Bin="$SC_LINK"
|
||||
Subconverter_Ready=false
|
||||
|
||||
# 配置项(可放 .env)
|
||||
# 配置项(可写入 .env)
|
||||
SUBCONVERTER_MODE="${SUBCONVERTER_MODE:-daemon}" # daemon | off
|
||||
SUBCONVERTER_HOST="${SUBCONVERTER_HOST:-127.0.0.1}"
|
||||
SUBCONVERTER_PORT="${SUBCONVERTER_PORT:-25500}"
|
||||
SUBCONVERTER_URL="${SUBCONVERTER_URL:-http://${SUBCONVERTER_HOST}:${SUBCONVERTER_PORT}}"
|
||||
|
||||
# pref.ini:不存在就从示例生成
|
||||
# pref.ini:不存在则从示例生成
|
||||
SUBCONVERTER_PREF="${SUBCONVERTER_PREF:-$SC_DIR/pref.ini}"
|
||||
PREF_EXAMPLE_INI="$SC_DIR/pref.example.ini"
|
||||
|
||||
PID_FILE="$Temp_Dir/subconverter.pid"
|
||||
|
||||
log() { echo "[subc] $*"; }
|
||||
warn() { echo "[subc][WARN] $*" >&2; }
|
||||
warn() { echo "[subc][警告] $*" >&2; }
|
||||
|
||||
detect_os() {
|
||||
local u
|
||||
@@ -58,7 +58,6 @@ detect_arch() {
|
||||
}
|
||||
|
||||
pick_platform_bin() {
|
||||
# 你的仓库结构:tools/subconverter/linux-amd64/subconverter 等
|
||||
local os="$1" arch="$2"
|
||||
local p="$SC_DIR/${os}-${arch}/subconverter"
|
||||
if [ -f "$p" ]; then
|
||||
@@ -78,7 +77,7 @@ make_stable_link_or_copy() {
|
||||
# 清理旧入口
|
||||
rm -f "$SC_LINK" 2>/dev/null || true
|
||||
|
||||
# 软链优先,不支持则复制
|
||||
# 优先创建软链接,失败则复制
|
||||
if ln -s "$src" "$SC_LINK" 2>/dev/null; then
|
||||
:
|
||||
else
|
||||
@@ -93,12 +92,12 @@ is_port_listening() {
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
ss -lnt | awk '{print $4}' | grep -q ":${port}\$" && return 0
|
||||
fi
|
||||
# 兜底:ss 不存在就不判断(返回 false)
|
||||
# 无检测工具则不判断
|
||||
return 1
|
||||
}
|
||||
|
||||
main() {
|
||||
# 0) 用户显式关闭
|
||||
# 0) 用户主动关闭
|
||||
if [ "$SUBCONVERTER_MODE" = "off" ]; then
|
||||
Subconverter_Ready=false
|
||||
export Subconverter_Bin Subconverter_Ready SUBCONVERTER_BIN SUBCONVERTER_READY SUBCONVERTER_URL
|
||||
@@ -112,7 +111,7 @@ main() {
|
||||
arch="$(detect_arch)"
|
||||
|
||||
if [ "$os" = "unsupported" ]; then
|
||||
warn "Unsupported OS: $(uname -s). Skip subconverter."
|
||||
warn "不支持的操作系统: $(uname -s),跳过 subconverter"
|
||||
Subconverter_Ready=false
|
||||
export Subconverter_Bin Subconverter_Ready SUBCONVERTER_BIN SUBCONVERTER_READY SUBCONVERTER_URL
|
||||
true
|
||||
@@ -120,7 +119,7 @@ main() {
|
||||
fi
|
||||
|
||||
if [ "$arch" = "unknown" ]; then
|
||||
warn "Unsupported arch: $(uname -m). Skip subconverter."
|
||||
warn "不支持的架构: $(uname -m),跳过 subconverter"
|
||||
Subconverter_Ready=false
|
||||
export Subconverter_Bin Subconverter_Ready SUBCONVERTER_BIN SUBCONVERTER_READY SUBCONVERTER_URL
|
||||
true
|
||||
@@ -129,16 +128,16 @@ main() {
|
||||
|
||||
platform_bin="$(pick_platform_bin "$os" "$arch")"
|
||||
if [ -z "$platform_bin" ]; then
|
||||
warn "No subconverter binary found at: $SC_DIR/${os}-${arch}/subconverter"
|
||||
warn "未找到 subconverter 二进制: $SC_DIR/${os}-${arch}/subconverter"
|
||||
Subconverter_Ready=false
|
||||
export Subconverter_Bin Subconverter_Ready SUBCONVERTER_BIN SUBCONVERTER_READY SUBCONVERTER_URL
|
||||
true
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 2) 生成稳定入口 tools/subconverter/subconverter
|
||||
# 2) 创建稳定入口
|
||||
if ! make_stable_link_or_copy "$platform_bin"; then
|
||||
warn "Failed to create stable entry: $SC_LINK"
|
||||
warn "创建稳定入口失败: $SC_LINK"
|
||||
Subconverter_Ready=false
|
||||
export Subconverter_Bin Subconverter_Ready SUBCONVERTER_BIN SUBCONVERTER_READY SUBCONVERTER_URL
|
||||
true
|
||||
@@ -147,45 +146,40 @@ main() {
|
||||
|
||||
Subconverter_Bin="$SC_LINK"
|
||||
Subconverter_Ready=true
|
||||
log "Resolved platform bin: ${os}-${arch} -> $Subconverter_Bin"
|
||||
log "已解析平台二进制: ${os}-${arch} -> $Subconverter_Bin"
|
||||
|
||||
# 3) pref.ini 生成(仅当准备启用 daemon)
|
||||
# 3) 生成 pref.ini(仅 daemon 模式)
|
||||
if [ "$Subconverter_Ready" = "true" ] && [ "$SUBCONVERTER_MODE" = "daemon" ]; then
|
||||
if [ ! -f "$SUBCONVERTER_PREF" ] && [ -f "$PREF_EXAMPLE_INI" ]; then
|
||||
cp -f "$PREF_EXAMPLE_INI" "$SUBCONVERTER_PREF"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 4) daemon 启动(只在需要时)
|
||||
# 4) 启动 daemon
|
||||
if [ "$Subconverter_Ready" = "true" ] && [ "$SUBCONVERTER_MODE" = "daemon" ]; then
|
||||
# pid 存活则认为已启动
|
||||
if [ -f "$PID_FILE" ] && kill -0 "$(cat "$PID_FILE" 2>/dev/null)" 2>/dev/null; then
|
||||
:
|
||||
else
|
||||
# 端口已监听则不重复起(可能是之前启动的)
|
||||
if is_port_listening "$SUBCONVERTER_PORT"; then
|
||||
:
|
||||
else
|
||||
(
|
||||
cd "$SC_DIR"
|
||||
# 注意:subconverter 读取 base/rules/snippets 等目录,必须在其目录下启动更稳
|
||||
nohup "$Subconverter_Bin" -f "$SUBCONVERTER_PREF" >/dev/null 2>&1 &
|
||||
echo $! > "$PID_FILE"
|
||||
)
|
||||
# 给一点点启动时间(不要长等,避免阻塞)
|
||||
sleep 0.2
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# 5) 统一导出(给后续脚本用)
|
||||
# 5) 导出变量
|
||||
export Subconverter_Bin
|
||||
export Subconverter_Ready
|
||||
export SUBCONVERTER_BIN="$Subconverter_Bin"
|
||||
export SUBCONVERTER_READY="$Subconverter_Ready"
|
||||
export SUBCONVERTER_URL
|
||||
|
||||
# 永不失败
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
+11
-11
@@ -20,19 +20,19 @@ for arg in "$@"; do
|
||||
--foreground) FOREGROUND=true ;;
|
||||
--daemon) DAEMON=true ;;
|
||||
*)
|
||||
echo "[ERROR] Unknown arg: $arg" >&2
|
||||
echo "[ERROR] 未知参数: $arg" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$FOREGROUND" = true ] && [ "$DAEMON" = true ]; then
|
||||
echo "[ERROR] Cannot use both --foreground and --daemon" >&2
|
||||
echo "[ERROR] 不能同时使用 --foreground 和 --daemon" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ "$FOREGROUND" = false ] && [ "$DAEMON" = false ]; then
|
||||
echo "[ERROR] Must specify --foreground or --daemon" >&2
|
||||
echo "[ERROR] 必须指定 --foreground 或 --daemon" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
@@ -40,12 +40,12 @@ fi
|
||||
# 基础校验
|
||||
# =========================
|
||||
if [ ! -s "$CONFIG_FILE" ]; then
|
||||
echo "[ERROR] runtime config not found: $CONFIG_FILE" >&2
|
||||
echo "[错ERROR误] 未找到运行配置文件: $CONFIG_FILE" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if grep -q '\${' "$CONFIG_FILE"; then
|
||||
echo "[ERROR] unresolved placeholder found in $CONFIG_FILE" >&2
|
||||
echo "[ERROR] 配置文件存在未替换变量: $CONFIG_FILE" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
@@ -65,15 +65,15 @@ source "$PROJECT_DIR/scripts/service_lib.sh"
|
||||
CLASH_BIN="$(resolve_clash_bin "$PROJECT_DIR" "${CpuArch:-}")"
|
||||
|
||||
if [ ! -x "$CLASH_BIN" ]; then
|
||||
echo "[ERROR] clash binary not executable: $CLASH_BIN" >&2
|
||||
echo "[ERROR] Clash 二进制不可执行: $CLASH_BIN" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# =========================
|
||||
# config 测试(唯一一次)
|
||||
# 配置校验(仅执行一次)
|
||||
# =========================
|
||||
if ! "$CLASH_BIN" -t -f "$CONFIG_FILE" -d "$RUNTIME_DIR" >/dev/null 2>&1; then
|
||||
echo "[ERROR] clash config test failed: $CONFIG_FILE" >&2
|
||||
echo "[ERROR] Clash 配置校验失败: $CONFIG_FILE" >&2
|
||||
write_run_state "failed" "config-test"
|
||||
exit 2
|
||||
fi
|
||||
@@ -87,13 +87,13 @@ if [ "$FOREGROUND" = true ]; then
|
||||
fi
|
||||
|
||||
# =========================
|
||||
# 后台模式(script)
|
||||
# 后台模式(脚本)
|
||||
# =========================
|
||||
cleanup_dead_pid
|
||||
|
||||
if is_script_running; then
|
||||
pid="$(read_pid 2>/dev/null || true)"
|
||||
echo "[INFO] clash already running, pid=${pid:-unknown}"
|
||||
echo "[INFO] Clash 已在运行,pid=${pid:-未知}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -104,4 +104,4 @@ echo "$pid" > "$PID_FILE"
|
||||
|
||||
write_run_state "running" "script" "$pid"
|
||||
|
||||
echo "[OK] Clash started in script mode, pid=$pid"
|
||||
echo "[SUCCESS] 已以脚本模式启动 Clash,pid=$pid"
|
||||
+13
-13
@@ -16,8 +16,8 @@ for arg in "$@"; do
|
||||
PURGE=true
|
||||
;;
|
||||
*)
|
||||
echo "[ERROR] Unknown arg: $arg" >&2
|
||||
echo "Usage: uninstall.sh [--purge]" >&2
|
||||
echo "[ERROR] 未知参数: $arg" >&2
|
||||
echo "用法: uninstall.sh [--purge]" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
@@ -29,11 +29,11 @@ warn() { log "\033[33m[WARN]\033[0m $*"; }
|
||||
err() { log "\033[31m[ERROR]\033[0m $*"; }
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
err "需要 root 权限执行卸载"
|
||||
err "卸载需要 root 权限"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[INFO] uninstalling clash-for-linux..."
|
||||
echo "[INFO] 正在卸载 clash-for-linux..."
|
||||
|
||||
# =========================
|
||||
# 停止服务
|
||||
@@ -52,12 +52,12 @@ if [ -f "$PID_FILE" ]; then
|
||||
PID="$(cat "$PID_FILE" 2>/dev/null || true)"
|
||||
|
||||
if [ -n "${PID:-}" ] && kill -0 "$PID" 2>/dev/null; then
|
||||
echo "[INFO] stopping pid=$PID"
|
||||
echo "[INFO] 正在停止进程 pid=$PID"
|
||||
kill "$PID" 2>/dev/null || true
|
||||
sleep 1
|
||||
|
||||
if kill -0 "$PID" 2>/dev/null; then
|
||||
echo "[WARN] force kill -9 $PID"
|
||||
echo "[WARN] 强制结束进程 -9 $PID"
|
||||
kill -9 "$PID" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
@@ -70,7 +70,7 @@ fi
|
||||
# =========================
|
||||
if [ -f "$UNIT_PATH" ]; then
|
||||
rm -f "$UNIT_PATH"
|
||||
ok "removed systemd unit"
|
||||
ok "已移除 systemd 服务"
|
||||
fi
|
||||
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
@@ -84,7 +84,7 @@ fi
|
||||
rm -f "$CLASHCTL_LINK" >/dev/null 2>&1 || true
|
||||
rm -f "$PROFILED_FILE" >/dev/null 2>&1 || true
|
||||
|
||||
ok "removed command + env"
|
||||
ok "已清理命令入口及环境变量"
|
||||
|
||||
# =========================
|
||||
# 删除安装目录
|
||||
@@ -92,14 +92,14 @@ ok "removed command + env"
|
||||
if [ "$PURGE" = true ]; then
|
||||
if [ -d "$INSTALL_DIR" ]; then
|
||||
rm -rf "$INSTALL_DIR"
|
||||
ok "removed install dir: $INSTALL_DIR"
|
||||
ok "已删除安装目录: $INSTALL_DIR"
|
||||
else
|
||||
warn "install dir not found: $INSTALL_DIR"
|
||||
warn "未找到安装目录: $INSTALL_DIR"
|
||||
fi
|
||||
else
|
||||
warn "install dir preserved: $INSTALL_DIR"
|
||||
echo "run with --purge to remove it"
|
||||
warn "安装目录已保留: $INSTALL_DIR"
|
||||
echo "如需彻底删除,请执行:bash uninstall.sh --purge"
|
||||
fi
|
||||
|
||||
echo
|
||||
ok "uninstall complete"
|
||||
ok "卸载完成"
|
||||
Reference in New Issue
Block a user