新服务器环境配置常常因网络不稳定和重复手动操作耗费大量时间。这个一键脚本侧重容错与兼容:自动检测网络并切换镜像源,修复因中断导致的 Antidote 损坏安装,保留已有的 DeepSeek API Key,并生成模块化的 .zshrc 配置以加速启动。脚本对常见包管理器做兼容处理,使用轻量级的网络探测与二次验证策略提高在国内服务器上的成功率,同时在 AI 补全部分采用无额外依赖的 Python 调用与交互式选择,保证可用性与最小外部依赖。

使用方式

保存为 init-zsh.sh,赋予可执行权限后运行:

1
bash init-zsh.sh

脚本会尝试保留已有 API Key(若存在),完成后执行 source ~/.zshrc 激活配置。测试 AI 功能示例:在终端输入 ? 如何查找大于100MB的文件,选择返回的命令即可执行。

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
#!/bin/bash

# 定义颜色
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

echo -e "${BLUE}=== DeepSeek Zsh 环境修复/安装脚本 ===${NC}"

# --- 1. 网络与环境检测 ---
echo -e "${YELLOW}[1/6] 检测网络环境...${NC}"
IS_CN=false
if curl -I -s --connect-timeout 3 https://www.google.com > /dev/null; then
echo -e "${GREEN}国际网络畅通${NC}"
else
echo -e "${YELLOW}国内网络环境 -> 启用加速镜像${NC}"
IS_CN=true
fi

# --- 2. 确保 Git 安装 ---
if ! command -v git &> /dev/null; then
echo -e "${RED}未找到 git,正在尝试安装...${NC}"
if command -v apt-get &> /dev/null; then
apt-get update && apt-get install -y git
elif command -v yum &> /dev/null; then
yum install -y git
elif command -v pacman &> /dev/null; then
pacman -S --noconfirm git
elif command -v apk &> /dev/null; then
apk add git
else
echo -e "${RED}无法自动安装 git,请手动安装后重试。${NC}"
exit 1
fi
fi

# --- 3. 修复 Antidote (核心步骤) ---
echo -e "${YELLOW}[2/6] 安装/修复 Antidote...${NC}"

ANTIDOTE_DIR="$HOME/.antidote"
# 如果目录存在但文件缺失,视为损坏,直接删除
if [ -d "$ANTIDOTE_DIR" ] && [ ! -f "$ANTIDOTE_DIR/antidote.zsh" ]; then
echo -e "${RED}发现损坏的 Antidote 安装,正在清理...${NC}"
rm -rf "$ANTIDOTE_DIR"
fi

if [ ! -d "$ANTIDOTE_DIR" ]; then
if [ "$IS_CN" = true ]; then
echo "尝试从镜像站克隆..."
git clone --depth=1 https://mirror.ghproxy.com/https://github.com/mattmc3/antidote.git "$ANTIDOTE_DIR"
fi

# 如果镜像站失败(或不是国内环境),尝试官方源
if [ ! -f "$ANTIDOTE_DIR/antidote.zsh" ]; then
echo "尝试从 GitHub 官方克隆..."
rm -rf "$ANTIDOTE_DIR" # 清理可能的空目录
git clone --depth=1 https://github.com/mattmc3/antidote.git "$ANTIDOTE_DIR"
fi
fi

# 最终检查
if [ ! -f "$ANTIDOTE_DIR/antidote.zsh" ]; then
echo -e "${RED}❌ 致命错误: Antidote 下载失败。${NC}"
echo -e "请检查网络连接 (是否能访问 github.com)。"
exit 1
else
echo -e "${GREEN}✅ Antidote 安装确认成功${NC}"
fi

# --- 4. 修复 Oh My Zsh ---
echo -e "${YELLOW}[3/6] 检查 Oh My Zsh...${NC}"
if [ ! -d "$HOME/.oh-my-zsh" ]; then
URL="https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh"
[ "$IS_CN" = true ] && URL="https://gitee.com/mirrors/oh-my-zsh/raw/master/tools/install.sh"

sh -c "$(curl -fsSL $URL)" "" --unattended
fi

# --- 5. 配置插件列表 ---
echo -e "${YELLOW}[4/6] 刷新插件列表...${NC}"
cat << EOF > "$HOME/.zsh_plugins.txt"
ohmyzsh/ohmyzsh path:lib
ohmyzsh/ohmyzsh path:plugins/git
zsh-users/zsh-autosuggestions
zsh-users/zsh-syntax-highlighting
romkatv/powerlevel10k
EOF

# --- 6. 生成 .zshrc ---
echo -e "${YELLOW}[5/6] 写入配置文件...${NC}"
# 保留用户之前的 Key (如果存在)
OLD_KEY=$(grep "AI_API_KEY=" "$HOME/.zshrc" 2>/dev/null | cut -d'"' -f2)

# 如果没有旧 Key,询问新 Key
if [[ -z "$OLD_KEY" || "$OLD_KEY" == "PLACEHOLDER_API_KEY" ]]; then
echo -n "请输入 DeepSeek API Key (回车跳过): "
read AI_KEY_INPUT
[ -z "$AI_KEY_INPUT" ] && AI_KEY_INPUT="PLACEHOLDER_API_KEY"
else
AI_KEY_INPUT="$OLD_KEY"
echo -e "${GREEN}检测到已有 API Key,已自动保留。${NC}"
fi

cat << 'EOF' > "$HOME/.zshrc"
# Powerlevel10k Instant Prompt
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi

export ZSH="$HOME/.oh-my-zsh"
ZSH_THEME="robbyrussell"
plugins=(git)
source $ZSH/oh-my-zsh.sh

# --- Antidote & P10k ---
zsh_plugins=${ZDOTDIR:-$HOME}/.zsh_plugins.txt
zsh_plugins_static=${ZDOTDIR:-$HOME}/.zsh_plugins.zsh

# 容错加载 Antidote
if [[ -f "$HOME/.antidote/antidote.zsh" ]]; then
source "$HOME/.antidote/antidote.zsh"
# 自动安装新插件
if [[ ! $zsh_plugins_static -nt $zsh_plugins ]]; then
antidote bundle < $zsh_plugins > $zsh_plugins_static
fi
source $zsh_plugins_static
else
echo "⚠️ Antidote 未找到,跳过插件加载"
fi

[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh

# --- AI DeepSeek Config ---
export AI_API_KEY="PLACEHOLDER_API_KEY"
export AI_API_URL="https://api.deepseek.com/chat/completions"
export AI_MODEL="deepseek-chat"

_ai_interactive_smart() {
if ! command -v fzf &> /dev/null; then return; fi
if [[ "$BUFFER" =~ ^[??] ]]; then
local query=$(echo "$BUFFER" | sed 's/^[??]*//; s/ at [0-9].*//' | xargs)
if [[ -z "$query" ]]; then return; fi
echo -n "\n🧠 Thinking..."
local python_script="
import sys, json, urllib.request, socket, os
socket.setdefaulttimeout(15)
try:
key = os.environ.get('AI_API_KEY', '')
if not key or 'PLACEHOLDER' in key:
print('ERR_NO_KEY')
sys.exit()
data = {
'model': '$AI_MODEL',
'messages': [
{'role': 'system', 'content': 'You are a Zsh CLI expert. Return ONLY commands (one per line) or @@TEXT@@ for explanations. Current OS: ' + os.uname().sysname},
{'role': 'user', 'content': '$query'}
],
'temperature': 0.1
}
req = urllib.request.Request('$AI_API_URL', json.dumps(data).encode('utf-8'))
req.add_header('Content-Type', 'application/json')
req.add_header('Authorization', 'Bearer ' + key)
with urllib.request.urlopen(req) as response:
js = json.loads(response.read().decode('utf-8'))
print(js['choices'][0]['message']['content'].strip().replace('\`\`\`bash','').replace('\`\`\`',''))
except Exception as e:
print('SYS_ERR:' + str(e))
"
local result=$(python3 -c "$python_script")
if [[ "$result" == "ERR_NO_KEY" ]]; then
echo -n "\n❌ 请设置 AI_API_KEY"
zle redisplay; return
elif [[ "$result" == *"@@TEXT@@"* ]]; then
echo -e "\n\033[36m${result//@@TEXT@@/}\033[0m"
BUFFER=""; zle redisplay; return
elif [[ "$result" == "SYS_ERR"* ]]; then
echo -n "\n💥 $result"; zle redisplay; return
fi
zle -I
local selected=$(echo "$result" | fzf --height=30% --layout=reverse --prompt="Run: " --border)
if [[ -n "$selected" ]]; then BUFFER="$selected"; CURSOR=$#BUFFER; else BUFFER=""; zle redisplay; fi
else
zle .accept-line
fi
}
zle -N _ai_interactive_smart
bindkey "^M" _ai_interactive_smart
EOF

# 替换 Key
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' "s/PLACEHOLDER_API_KEY/$AI_KEY_INPUT/" "$HOME/.zshrc"
else
sed -i "s/PLACEHOLDER_API_KEY/$AI_KEY_INPUT/" "$HOME/.zshrc"
fi

echo -e "${GREEN}✅ 修复完成。${NC}"
echo -e "请执行: ${YELLOW}source ~/.zshrc${NC}${YELLOW}zsh${NC}"