uv + JupyterLab 在 WSL2 下的全局管理部署实践

uv + JupyterLab 在 WSL2 下的全局管理部署实践

上一篇文章我们已经把 Hexo + Cloudflare Pages 完全私有博客 搭好了。

这篇进入:用 uv(Rust 编写,比 pip 快 20 倍)全局管理环境 + JupyterLab(全中文交互式笔记工具)写深度学习笔记,并且一键把 .ipynb 发布到你的私有博客。


一、为什么选择 uv + JupyterLab?

1. uv:pip 的替代者,Python虚拟环境管理工具黑马

uv 是 Astral(ruff 作者)出品的 Rust 工具,比 pip 快 20 倍,支持 venv / poetry / conda 所有功能,还自动锁依赖(uv.lock)防止版本冲突。

工具 创建环境 安装 torch 锁文件 WSL2 体验 官方链接
venv+pip 2 秒 2 分钟 普通 -
conda 30 秒 3 分钟 -
uv 0.1 秒 8 秒 神级 https://docs.astral.sh/uv/

2. JupyterLab:AI 笔记终极工具

JupyterLab 是 Jupyter Notebook 的升级版,支持全中文、交互式代码、Plotly 图表、LaTeX 公式,一键导出 Markdown 完美适配 Hexo/Fluid 主题。


二、真实踩过的所有坑 + 最终解决方案


坑 1:uv 安装失败(GitHub SSL + 权限地狱)

错误表现

  • curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL
  • zsh: permission denied: uv (即使 chmod 755)
  • mv: same file (嵌套目录问题)

为什么会发生

  • 国内 GitHub SSL 不稳
  • WSL2 NTFS 挂载 + Windows Defender 安全标记导致 chmod 无效
  • uv 官方包结构为 uv/uv

发现过程

  • 先用官方 curl 脚本失败,改 wget 手动下载,解压后 permission denied。搜 “WSL2 uv permission denied”,发现 Super User #1512808 提到 Unblock-File,路径转换失败。
  • 我先用官方 curl 脚本,卡在 downloading uv 0.9.11 1 分钟不动。换 wget 手动下载,解压后 ls ~/uv/bin/ 只看到 uv-x86_64-unknown-linux-gnu,敲 uv 报 command not found。
  • chmod 755 后变成 permission denied。上网搜 “WSL2 uv permission denied”,发现 Stack Overflow #1512808 提到 Windows 安全标记,试 Unblock-File 失败(路径转换问题)。
  • 再搜 “uv tar.gz nested directory”,GitHub issue #3924 确认是官方打包问题,用 cp -f uv/uv /usr/local/bin/uv 解决,
  • 但 sudo cp 报 Permission denied。最终用 wslpath -w + Unblock-File + 复制到 /usr/local/bin 成功。

终极解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
# 手动下载(绕过 curl SSL)
wget https://github.com/astral-sh/uv/releases/download/0.9.11/uv-x86_64-unknown-linux-gnu.tar.gz
# 解压
tar -xzf uv-x86_64-unknown-linux-gnu.tar.gz
# 解除 Windows 安全标记 + 复制到系统 bin
powershell.exe -Command "Unblock-File -Path '$(wslpath -w /home/tom/uv/uv/uv)'"
sudo cp -f uv/uv /usr/local/bin/uv
sudo chmod 755 /usr/local/bin/uv
# 永久生效
echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
# 验证
uv --version

官方参考

uv 安装:https://docs.astral.sh/uv/getting-started/installation/
WSL2 权限问题:https://learn.microsoft.com/en-us/windows/wsl/filesystems#file-permissions
Windows 安全标记:https://superuser.com/questions/1512808/wsl2-unblock-file-from-windows-host


坑 2:zsh 幽灵缓存(最阴间!报错 defining function based on alias jupyter)

错误表现

1
2
3
/home/tom/.zshrc:6: defining function based on alias 'jupyter'
/home/tom/.zshrc:6: parse error near '()'
即使删了文件,重启终端还是报错

为什么会发生

zsh 用 hash table 缓存命令类型(alias / function / builtin),删了 alias 也不会立刻清缓存。一旦记住 jupyter 是 alias,即使你删了 alias 定义,zsh 还缓存着这个”记忆”,导致后续 function 定义时冲突。

发现过程

我改了 10 次 .zshrc,重启 5 次终端,仍然报错。搜 “zsh defining function based on alias”,发现 Stack Overflow #19343973 提到 hash -r,执行后成功。进一步查 zsh 手册,发现 hash -r 清除整个 hash table,hash -r jupyter 只清单个。

原理详解

  • zsh hash table 是内部数据结构,用于加速命令查找
  • 定义 alias jupyter=… 时,zsh 把 jupyter 哈希为 “alias 类型”
  • unalias 只删定义,但 hash table 残留旧条目
  • 重新 source ~/.zshrc 时,zsh 读取旧缓存,报 “defining function based on alias”

终极解决方案

1
2
3
4
5
6
# 清除 zsh hash table(核心!)
hash -r
# 强制删除 jupyter的alias(保险)
unalias jupyter 2>/dev/null || true
# 重新加载
source ~/.zshrc

官方参考

zsh Hash Tables:https://zsh.sourceforge.io/Doc/Release/Parameters.html#index-hash
Stack Overflow:https://stackoverflow.com/questions/19343973/unaliasing-a-global-alias-in-zsh
Unix Stack Exchange 原理解析:https://unix.stackexchange.com/questions/33255/how-to-clear-the-command-cache-in-zsh
权威社区解析:https://unix.stackexchange.com/questions/161973/clear-or-disable-aliases-in-zsh (详细讨论 alias 冲突和 unalias -m ‘*’ 清除所有 alias)


坑 3:Jupyter 一键打开浏览器失败(wslpath + powershell)

错误表现

1
wslpath : 无法将“wslpath”项识别为 cmdlet

为什么会发生

wslpath 是 Linux 命令,Windows PowerShell 无此命令。

终极解法(从 HTML 提取 token)

1
powershell.exe -Command "Start-Process \"http://127.0.0.1:8888/lab?token=$(cat ~/.local/share/jupyter/runtime/jpserver-*-open.html | grep -o 'token=[^\"]*' | head -1)\""

官方参考

Jupyter token 文档:https://jupyter-server.readthedocs.io/en/latest/users/authentication.html#tokens


坑 4:uv 安装权限地狱(Windows Defender + NTFS 锁死)

错误表现

chmod 755 后仍然 permission denied

为什么会发生

  • WSL2 NTFS 挂载有 Windows 安全标记(Zone.Identifier)
  • chmod 在 NTFS 上不完全生效

最终解决办法

1
2
3
4
5
wget https://github.com/astral-sh/uv/releases/download/0.9.11/uv-x86_64-unknown-linux-gnu.tar.gz
tar -xzf uv-x86_64-unknown-linux-gnu.tar.gz
powershell.exe -Command "Unblock-File -Path '$(wslpath -w /home/tom/uv/uv/uv)'"
sudo cp -f uv/uv /usr/local/bin/uv
sudo chmod 755 /usr/local/bin/uv

官方参考

uv 安装:https://docs.astral.sh/uv/getting-started/installation/
WSL2 文件权限:https://learn.microsoft.com/en-us/windows51/wsl/filesystems#file-permissions


坑 5:Jupyter token 提取失败(grep 格式变了)

错误表现

  • grep -o ‘token=[^”]*’ 提取空
  • Start-Process URL 无效

为什么会发生

  • token 格式从 token=xxx"token=xxx&next=...
  • JupyterLab 5.0+ token 格式变了(token=… 后跟 & 或 ?)
  • grep 没匹配

发现过程

先用 grep -o ‘token=[^”]’,输出空。cat html 文件看格式,token=xxx&next=…。改 grep -o ‘token=[^&]’ 成功。

最终解决方案

1
grep -o 'token=[^&]*' ~/.local/share/jupyter/runtime/jpserver-*-open.html | head -1

官方参考

https://jupyterlab.readthedocs.io/en/stable/user/security.html


三、最终成功的完整流程

1. uv 全局安装

1
2
3
4
5
6
7
8
wget https://github.com/astral-sh/uv/releases/download/0.9.11/uv-x86_64-unknown-linux-gnu.tar.gz
tar -xzf uv-x86_64-unknown-linux-gnu.tar.gz
powershell.exe -Command "Unblock-File -Path '$(wslpath -w /home/tom/uv/uv/uv)'"
sudo cp -f uv/uv /usr/local/bin/uv
sudo chmod 755 /usr/local/bin/uv
echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
uv --version

2. JupyterLab 全局环境(uv 0.1 秒创建)

1
2
3
uv venv ~/uv/envs/jupyter-global
source ~/uv/envs/jupyter-global/bin/activate
uv pip install jupyterlab jupyterlab-language-pack-zh-CN numpy pandas matplotlib seaborn plotly scipy scikit-learn torch tensorflow

3. 一键启动 + 自动打开浏览器

生成脚本:

1
2
3
4
5
6
cat > ~/jupyter-uv.sh << 'EOF'
#!/bin/bash
source ~/uv/envs/jupyter-global/bin/activate
jupyter lab --no-browser --port=8888
EOF
chmod +x ~/jupyter-uv.sh

添加 zsh function:

1
2
echo 'jupyter() { ~/jupyter-uv.sh & sleep 1; powershell.exe -Command "Start-Process \"http://127.0.0.1:8888/lab?token=$(cat ~/.local/share/jupyter/runtime/jpserver-*-open.html | grep -o '\''token=[^&]*'\'' | head -1)\""; }' >> ~/.zshrc
source ~/.zshrc

4. 一键发布 .ipynb 到私有博客

1
2
3
4
5
6
7
echo 'jupush() { 
~/uv/envs/jupyter-global/bin/jupyter nbconvert --to markdown "$1" --output-dir=/home/tom/MyBlog/source/_posts
cd /home/tom/MyBlog
git add .
git commit -m "新笔记:${1%.*}"
git push
}' >> ~/.zshrc && source ~/.zshrc

四、最终效果(每天只敲两个命令)

1
2
jupyter
jupush xxx.ipynb

uv + JupyterLab 在 WSL2 下的全局管理部署实践
http://example.com/2025/11/26/uv-JupyterLab部署/
Author
John Doe
Posted on
November 26, 2025
Licensed under