最近领了不少 Claude Code 镜像站的免费额度,但是各大镜像站的稳定性一般,有时候某个源用着用着就挂了,需要快速切换到其他可用的源;有时候想根据不同项目的需求选择性价比最高的源。每次手动修改环境变量或配置文件既麻烦又容易出错,特别是当手头有多个免费额度需要管理时,于是写了个简单的切换脚本来解决这个问题。

按照官方文档的说明,目前可以使用下面的命令来设置镜像源。

1
2
3
export ANTHROPIC_AUTH_TOKEN="your-token"
export ANTHROPIC_BASE_URL="https://api.anthropic.com"
source ~/.zshrc

但当某个源不可用的时候,或者是在使用多个源的时候,就需要多次查询源地址和密钥来切换更新。

脚本功能

  • 统一配置管理:使用 JSON 配置文件统一管理所有 API 源。

  • 智能价格排序:脚本会自动解析价格信息:

    • 自动识别人民币(¥)和美元($)价格
    • 按照 1:7 汇率自动转换美元为人民币
    • 按照性价比从低到高自动排序显示
  • 当前状态检测:自动检测当前环境变量中的配置,在界面显示当前使用的源。

  • 双模式切换:提供两种切换模式:

    • 临时设置模式:仅当前会话生效,适合临时使用
    • 永久设置模式:写入配置文件
  • 智能环境识别:自动识别 zsh 或 bash 环境,选择正确的配置文件路径。

配置文件

脚本使用一个 JSON 文件来存储所有源的配置信息,文件路径为 ~/.claude_config.json,格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"configs": [
{
"name": "官方源",
"token": "sk-ant-your-official-token",
"url": "https://api.anthropic.com",
"pricing": {
"input": "$3/1M tokens",
"output": "$15/1M tokens",
"description": "官方源,稳定性最佳,但价格较高"
}
},
{
"name": "中转源A",
"token": "your-proxy-token-a",
"url": "https://api-proxy-a.example.com",
"pricing": {
"input": "¥1.8/1M tokens",
"output": "¥9.0/1M tokens",
"description": "性价比较高,速度一般"
}
}
]
}

安装说明

脚本依赖两个工具:

  • jq:用于JSON文件解析
  • bc:用于价格计算和数值比较

安装依赖

1
2
3
4
5
# macOS
brew install jq bc

# Ubuntu/Debian
sudo apt install jq bc

使用方式

1
2
3
4
5
6
7
8
9
10
# 永久设置模式
./claude-switch.sh

# 临时设置模式
source ./claude-switch.sh

# 设置为全局命令
mkdir -p ~/bin
cp claude-switch.sh ~/bin/cs
echo 'export PATH="$HOME/bin:$PATH"' >> ~/.zshrc

脚本内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#!/bin/bash

# 清除屏幕内容
clear

# 配置文件路径
CONFIG_FILE="$(dirname "$0")/claude_configs.json"

# 检查配置文件是否存在
if [[ ! -f "$CONFIG_FILE" ]]; then
echo "[Error] 配置文件不存在: $CONFIG_FILE"
echo "请创建配置文件,JSON格式"
exit 1
fi

# 检查是否通过source运行
echo "=========================================="
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
echo "Claude 配置切换工具"
echo "永久设置模式"
FORCE_PERMANENT=true
TEMP_SETTING_AVAILABLE=false
else
echo "Claude 配置切换工具"
echo ""
TEMP_SETTING_AVAILABLE=true
fi
echo "作者:Lynn v1.4.0"
echo "=========================================="

# 检查jq是否可用
if ! command -v jq &> /dev/null; then
echo "[Error] 需要安装jq来解析JSON文件"
echo "macOS: brew install jq"
echo "Ubuntu: sudo apt install jq"
exit 1
fi

# 读取配置文件并显示选项
echo ""

# 获取配置数量
config_count=$(jq '.configs | length' "$CONFIG_FILE")

# 创建临时文件来存储排序后的配置
temp_file=$(mktemp)

# 将配置信息写入临时文件,包含索引信息
for ((i=0; i<config_count; i++)); do
name=$(jq -r ".configs[$i].name" "$CONFIG_FILE")
input_price=$(jq -r ".configs[$i].pricing.input" "$CONFIG_FILE")
output_price=$(jq -r ".configs[$i].pricing.output" "$CONFIG_FILE")
description=$(jq -r ".configs[$i].pricing.description" "$CONFIG_FILE")

# 提取价格数字用于排序(处理 ¥0.9/1M tokens 或 $3/1M tokens 格式)
input_num=$(echo "$input_price" | grep -o '[0-9]*\.\?[0-9]*' | head -1)
output_num=$(echo "$output_price" | grep -o '[0-9]*\.\?[0-9]*' | head -1)

# 如果无法提取数字,使用0
input_num=${input_num:-0}
output_num=${output_num:-0}

# 检查是否为美元价格,如果是则乘以7转换为人民币
if [[ "$input_price" == *"$"* ]]; then
input_num=$(echo "$input_num * 7" | bc -l 2>/dev/null || echo "$input_num")
fi
if [[ "$output_price" == *"$"* ]]; then
output_num=$(echo "$output_num * 7" | bc -l 2>/dev/null || echo "$output_num")
fi

# 计算总价格(输入+输出)
total_price=$(echo "$input_num + $output_num" | bc -l 2>/dev/null || echo "0")

echo "$i|$name|$input_price|$output_price|$description|$total_price" >> "$temp_file"
done

# 按总价格排序(从低到高)
if command -v bc &> /dev/null; then
sort -t'|' -k6,6n "$temp_file" > "${temp_file}.sorted"
mv "${temp_file}.sorted" "$temp_file"
else
echo "[Warning] 未找到bc命令,将按原始顺序显示"
fi

# 显示排序后的配置
line_num=1
while IFS='|' read -r index name input_price output_price description total_price; do
echo "$line_num) $name"
echo " 输入: $input_price | 输出: $output_price"

# 计算并显示转换后的人民币价格
input_num=$(echo "$input_price" | grep -o '[0-9]*\.\?[0-9]*' | head -1)
output_num=$(echo "$output_price" | grep -o '[0-9]*\.\?[0-9]*' | head -1)
input_num=${input_num:-0}
output_num=${output_num:-0}

# 检查是否为美元价格,如果是则乘以7转换为人民币
if [[ "$input_price" == *"$"* ]]; then
input_cny=$(echo "$input_num * 7" | bc -l 2>/dev/null || echo "$input_num")
output_cny=$(echo "$output_num * 7" | bc -l 2>/dev/null || echo "$output_num")
echo " (约 ¥${input_cny}/1M tokens | ¥${output_cny}/1M tokens)"
fi

# 只有当描述不为空且不是null时才显示
if [[ -n "$description" && "$description" != "null" ]]; then
echo " $description"
fi
echo ""

# 保存索引映射
eval "config_index_$line_num=$index"

line_num=$((line_num + 1))
done < "$temp_file"

# 清理临时文件
rm -f "$temp_file"

# 获取当前配置名称
current_config_name=""
if [[ -n "$ANTHROPIC_AUTH_TOKEN" && -n "$ANTHROPIC_BASE_URL" ]]; then
config_count=$(jq '.configs | length' "$CONFIG_FILE")
for ((i=0; i<config_count; i++)); do
token=$(jq -r ".configs[$i].token" "$CONFIG_FILE")
url=$(jq -r ".configs[$i].url" "$CONFIG_FILE")
if [[ "$token" == "$ANTHROPIC_AUTH_TOKEN" && "$url" == "$ANTHROPIC_BASE_URL" ]]; then
current_config_name=$(jq -r ".configs[$i].name" "$CONFIG_FILE")
break
fi
done
fi

# 在列表末尾显示当前设置
if [[ -n "$current_config_name" ]]; then
echo "当前设置:$current_config_name"
else
echo "当前设置:未配置"
fi
echo "=========================================="

read -p "#? " choice

if [[ -z "$FORCE_PERMANENT" ]]; then
echo ""
echo "请选择设置方式:"
echo "1) 临时设置 (仅当前终端会话有效)"
echo "2) 永久设置 (写入配置文件)"

read -p "设置方式 [1/2]: " mode
else
mode="2"
fi

# 验证选择并获取配置
if [[ $choice -ge 1 && $choice -le $((line_num-1)) ]]; then
# 使用保存的索引映射
eval "index=\$config_index_$choice"
CONFIG_NAME=$(jq -r ".configs[$index].name" "$CONFIG_FILE")
TOKEN=$(jq -r ".configs[$index].token" "$CONFIG_FILE")
BASE_URL=$(jq -r ".configs[$index].url" "$CONFIG_FILE")
else
echo "[Error] 无效选择"
exit 1
fi

if [ "$mode" = "1" ]; then
# 临时设置
export ANTHROPIC_AUTH_TOKEN="$TOKEN"
export ANTHROPIC_BASE_URL="$BASE_URL"
echo "已切换到: $CONFIG_NAME (临时设置)"
echo "仅在当前终端会话中有效"
elif [ "$mode" = "2" ]; then
# 永久设置
# 检测当前shell类型
if [ -n "$ZSH_VERSION" ] || [ "$SHELL" = "/bin/zsh" ] || [ "$SHELL" = "/usr/bin/zsh" ]; then
CONFIG_FILE="$HOME/.zshrc"
else
CONFIG_FILE="$HOME/.bash_profile"
fi

echo "切换配置任务清单:"
echo "□ 写入配置到: $CONFIG_FILE"

# 移除旧的配置(如果存在)
grep -v "ANTHROPIC_AUTH_TOKEN=" "$CONFIG_FILE" > "$CONFIG_FILE.tmp" 2>/dev/null || touch "$CONFIG_FILE.tmp"
grep -v "ANTHROPIC_BASE_URL=" "$CONFIG_FILE.tmp" > "$CONFIG_FILE.tmp2"
mv "$CONFIG_FILE.tmp2" "$CONFIG_FILE"
rm -f "$CONFIG_FILE.tmp"

# 添加新配置
echo "export ANTHROPIC_AUTH_TOKEN=\"$TOKEN\"" >> "$CONFIG_FILE"
echo "export ANTHROPIC_BASE_URL=\"$BASE_URL\"" >> "$CONFIG_FILE"

# 清除上一行并显示完成状态
echo -en "\033[1A\033[K"
echo "■ 配置已写入: $CONFIG_FILE"
echo "□ 刷新配置生效"

# 自动刷新zsh配置
if [ -n "$ZSH_VERSION" ] || [ "$SHELL" = "/bin/zsh" ] || [ "$SHELL" = "/usr/bin/zsh" ]; then
source /Users/lynn/.zshrc
# 清除上一行并显示完成状态
echo -en "\033[1A\033[K"
echo "■ 配置已自动刷新生效"
echo ""
echo "✓ 已切换到: $CONFIG_NAME (永久设置)"
else
echo "■ 配置已写入完成"
echo ""
echo "✓ 已切换到: $CONFIG_NAME (永久设置)"
echo " 要立即生效,请运行: source $CONFIG_FILE"
echo " 或者重新打开终端"
fi
else
echo "[Error] 无效的设置方式选择"
exit 1
fi

后记

如果你喜欢我的文章,可以考虑在爱发电赞助我,这会激励我更有动力地写更多的文章。

爱发电:https://afdian.net/a/lynnguo666


本站由 Lynn 使用 Stellar 1.33.1 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。