mirror of
https://github.com/wnlen/clash-for-linux.git
synced 2026-02-04 10:11:28 +08:00
Add subscription management, mixin, and tun support
This commit is contained in:
174
clashctl
174
clashctl
@ -32,6 +32,7 @@ resolve_clash_home() {
|
||||
CLASH_HOME=$(resolve_clash_home)
|
||||
ENV_FILE="$CLASH_HOME/.env"
|
||||
PID_FILE="$CLASH_HOME/temp/clash.pid"
|
||||
SUBSCRIPTION_FILE="$CLASH_HOME/conf/subscriptions.list"
|
||||
|
||||
use_systemd() {
|
||||
command -v systemctl >/dev/null 2>&1
|
||||
@ -58,30 +59,157 @@ Commands:
|
||||
status Show Clash service status
|
||||
update Refresh subscription config
|
||||
set-url <url> Update CLASH_URL in .env
|
||||
sub add <name> <url> [headers] Add subscription entry
|
||||
sub del <name> Delete subscription entry
|
||||
sub use <name> Activate subscription entry
|
||||
sub update [name] Update subscription config by entry
|
||||
sub list List subscriptions
|
||||
sub log Show subscription update logs
|
||||
|
||||
Environment:
|
||||
CLASH_HOME Override Clash installation directory
|
||||
USAGE
|
||||
}
|
||||
|
||||
set_env_var() {
|
||||
local key="$1"
|
||||
local value="${2:-}"
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "[ERROR] 未找到 .env 文件: $ENV_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
local escaped
|
||||
escaped=$(printf "%s" "$value" | sed "s/'/'\"'\"'/g")
|
||||
if grep -q "^export ${key}=" "$ENV_FILE"; then
|
||||
sed -i "s@^export ${key}=.*@export ${key}='${escaped}'@" "$ENV_FILE"
|
||||
else
|
||||
echo "export ${key}='${escaped}'" >> "$ENV_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
set_url() {
|
||||
local url="$1"
|
||||
if [ -z "$url" ]; then
|
||||
echo "[ERROR] 请提供订阅地址" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "[ERROR] 未找到 .env 文件: $ENV_FILE" >&2
|
||||
set_env_var "CLASH_URL" "$url"
|
||||
set_env_var "CLASH_SUBSCRIPTION" ""
|
||||
echo "[OK] 已更新 CLASH_URL"
|
||||
}
|
||||
|
||||
ensure_subscription_file() {
|
||||
mkdir -p "$(dirname "$SUBSCRIPTION_FILE")"
|
||||
if [ ! -f "$SUBSCRIPTION_FILE" ]; then
|
||||
touch "$SUBSCRIPTION_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
subscription_lookup() {
|
||||
local name="$1"
|
||||
awk -F'|' -v target="$name" '$1 == target {print; exit}' "$SUBSCRIPTION_FILE"
|
||||
}
|
||||
|
||||
subscription_add() {
|
||||
local name="$1"
|
||||
local url="$2"
|
||||
local headers="${3:-}"
|
||||
if [ -z "$name" ] || [ -z "$url" ]; then
|
||||
echo "[ERROR] 用法: clashctl sub add <name> <url> [headers]" >&2
|
||||
exit 1
|
||||
fi
|
||||
local escaped
|
||||
escaped=$(printf "%s" "$url" | sed "s/'/'\"'\"'/g")
|
||||
if grep -q '^export CLASH_URL=' "$ENV_FILE"; then
|
||||
sed -i "s@^export CLASH_URL=.*@export CLASH_URL='${escaped}'@" "$ENV_FILE"
|
||||
else
|
||||
echo "export CLASH_URL='${escaped}'" >> "$ENV_FILE"
|
||||
ensure_subscription_file
|
||||
if subscription_lookup "$name" >/dev/null; then
|
||||
echo "[ERROR] 订阅已存在: $name" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "[OK] 已更新 CLASH_URL"
|
||||
printf "%s|%s|%s|-\n" "$name" "$url" "$headers" >> "$SUBSCRIPTION_FILE"
|
||||
echo "[OK] 已添加订阅: $name"
|
||||
}
|
||||
|
||||
subscription_del() {
|
||||
local name="$1"
|
||||
if [ -z "$name" ]; then
|
||||
echo "[ERROR] 用法: clashctl sub del <name>" >&2
|
||||
exit 1
|
||||
fi
|
||||
ensure_subscription_file
|
||||
if ! subscription_lookup "$name" >/dev/null; then
|
||||
echo "[ERROR] 未找到订阅: $name" >&2
|
||||
exit 1
|
||||
fi
|
||||
awk -F'|' -v target="$name" 'BEGIN{OFS=FS} $1 != target {print}' "$SUBSCRIPTION_FILE" > "${SUBSCRIPTION_FILE}.tmp"
|
||||
mv "${SUBSCRIPTION_FILE}.tmp" "$SUBSCRIPTION_FILE"
|
||||
echo "[OK] 已删除订阅: $name"
|
||||
}
|
||||
|
||||
subscription_use() {
|
||||
local name="$1"
|
||||
if [ -z "$name" ]; then
|
||||
echo "[ERROR] 用法: clashctl sub use <name>" >&2
|
||||
exit 1
|
||||
fi
|
||||
ensure_subscription_file
|
||||
local line
|
||||
line=$(subscription_lookup "$name")
|
||||
if [ -z "$line" ]; then
|
||||
echo "[ERROR] 未找到订阅: $name" >&2
|
||||
exit 1
|
||||
fi
|
||||
local url headers
|
||||
url=$(echo "$line" | awk -F'|' '{print $2}')
|
||||
headers=$(echo "$line" | awk -F'|' '{print $3}')
|
||||
set_env_var "CLASH_URL" "$url"
|
||||
set_env_var "CLASH_HEADERS" "$headers"
|
||||
set_env_var "CLASH_SUBSCRIPTION" "$name"
|
||||
echo "[OK] 已切换订阅: $name"
|
||||
}
|
||||
|
||||
subscription_touch() {
|
||||
local name="$1"
|
||||
local timestamp
|
||||
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
awk -F'|' -v target="$name" -v ts="$timestamp" 'BEGIN{OFS=FS} {if ($1==target) {$4=ts} print}' "$SUBSCRIPTION_FILE" > "${SUBSCRIPTION_FILE}.tmp"
|
||||
mv "${SUBSCRIPTION_FILE}.tmp" "$SUBSCRIPTION_FILE"
|
||||
}
|
||||
|
||||
subscription_update() {
|
||||
local name="${1:-}"
|
||||
if [ -z "$name" ]; then
|
||||
name=$(awk -F= '/^export CLASH_SUBSCRIPTION=/{print $2}' "$ENV_FILE" | tr -d "'" | tr -d '"')
|
||||
fi
|
||||
if [ -z "$name" ]; then
|
||||
echo "[ERROR] 未指定订阅名称,且 CLASH_SUBSCRIPTION 未设置" >&2
|
||||
exit 1
|
||||
fi
|
||||
subscription_use "$name"
|
||||
run_script update.sh
|
||||
subscription_touch "$name"
|
||||
echo "[OK] 订阅已更新: $name"
|
||||
}
|
||||
|
||||
subscription_list() {
|
||||
ensure_subscription_file
|
||||
local active
|
||||
active=$(awk -F= '/^export CLASH_SUBSCRIPTION=/{print $2}' "$ENV_FILE" | tr -d "'" | tr -d '"')
|
||||
printf "%-20s %-6s %s\n" "NAME" "ACTIVE" "URL"
|
||||
while IFS='|' read -r name url headers updated; do
|
||||
[ -z "$name" ] && continue
|
||||
if [ "$name" = "$active" ]; then
|
||||
printf "%-20s %-6s %s\n" "$name" "yes" "$url"
|
||||
else
|
||||
printf "%-20s %-6s %s\n" "$name" "no" "$url"
|
||||
fi
|
||||
done < "$SUBSCRIPTION_FILE"
|
||||
}
|
||||
|
||||
subscription_log() {
|
||||
ensure_subscription_file
|
||||
printf "%-20s %s\n" "NAME" "LAST_UPDATE"
|
||||
while IFS='|' read -r name url headers updated; do
|
||||
[ -z "$name" ] && continue
|
||||
printf "%-20s %s\n" "$name" "${updated:--}"
|
||||
done < "$SUBSCRIPTION_FILE"
|
||||
}
|
||||
|
||||
status_fallback() {
|
||||
@ -135,6 +263,34 @@ case "$command" in
|
||||
set-url)
|
||||
set_url "${2:-}"
|
||||
;;
|
||||
sub)
|
||||
subcommand="${2:-}"
|
||||
case "$subcommand" in
|
||||
add)
|
||||
subscription_add "${3:-}" "${4:-}" "${5:-}"
|
||||
;;
|
||||
del|delete|rm|remove)
|
||||
subscription_del "${3:-}"
|
||||
;;
|
||||
use)
|
||||
subscription_use "${3:-}"
|
||||
;;
|
||||
update)
|
||||
subscription_update "${3:-}"
|
||||
;;
|
||||
list|ls)
|
||||
subscription_list
|
||||
;;
|
||||
log)
|
||||
subscription_log
|
||||
;;
|
||||
*)
|
||||
echo "[ERROR] 未知订阅命令: $subcommand" >&2
|
||||
print_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
-h|--help|help|'')
|
||||
print_usage
|
||||
;;
|
||||
|
||||
Reference in New Issue
Block a user