news 2026/10/1 1:41:11

WSL2安装、迁移与权限配置:解决C盘膨胀和默认用户丢失

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WSL2安装、迁移与权限配置:解决C盘膨胀和默认用户丢失

上周帮同事看一台开发机,C 盘只剩 3 个 G,红色警告。打开资源管理器一层层翻下去,元凶是一个叫ext4.vhdx的文件,八十多个 G,躺在他用户目录的AppData\Local\Packages底下。他一脸茫然:我就用 WSL 装了个 Ubuntu 跑 Python,怎么就吃掉一整块盘了?

这个问题我遇到过太多次。WSL 好用是真的好用,但它默认把所有发行版塞进 C 盘,装完就不管了;等你反应过来,.vscode-server、pip 缓存、conda 环境、Docker 镜像层层叠加,C 盘就废了。这篇就按我实际操作的顺序,把 WSL 从零装好、整体搬到 D 盘、设好默认登录用户、配好 root 密码和 sudo 权限这一整条链路讲透,顺带把 VSCode 联动、终端字体这些日常体验相关的东西也一起捋一遍。不管你是刚听说 WSL 的新手,还是用了两年但一直没敢迁移的老用户,都能照着抄。

1. 动手之前先算两笔账:版本选型和磁盘占用

1.1 WSL1 和 WSL2 不是同一个东西的两代,而是两套实现

很多教程一上来就说"装 WSL2,别用 WSL1",但不讲为什么。这个为什么很重要,因为它直接决定你后面会不会踩坑。

WSL1 是把 Linux 系统调用实时翻译成 Windows 系统调用,本质上是一个兼容层,没有一个真正的 Linux 内核。好处是它的文件系统是直接跑在 NTFS 上的,所以你访问/mnt/c/xxx的时候速度飞快,跟原生 Windows 程序读写同一个文件几乎没差别;内存占用也小。

WSL2 则是跑了一个轻量虚拟机,里面是一个微软编译的真实 Linux 内核。它的系统调用是完整的,Docker 能跑、systemd 能开、binwalk这类需要特殊内核能力的工具不会莫名其妙报错,兼容性基本等于一台真机。代价是两件事:跨文件系统访问变慢(访问/mnt/c要经过 9P 协议转发,IO 性能大概只有原生的十分之一到五分之一),以及内存会被虚拟机吃掉一块且不会自动归还。

我的判断标准很简单:

你的场景建议
跑编译、跑 Docker、跑 CUDA、需要 systemdWSL2,没得选
项目文件必须留在 Windows 盘、频繁跨系统读写慎重,或者接受 WSL2 的跨盘慢
只是想要个 grep/sed/awk 工具集WSL1 其实够用

不过现实是现在装的时候默认就是 WSL2,而且 WSL1 已经停止功能更新,新项目直接 WSL2 就行。真正要注意的是虚拟化功能必须打开,WSL2 依赖它。任务管理器 → 性能 → CPU,右下角能看到"虚拟化:已启用"。如果显示已禁用,得进 BIOS 开 VT-x / AMD-V。另外如果你机器上同时还跑着老版本 VMware 或者 VirtualBox,可能会和 Hyper-V 平台抢占,表现为 WSL 启动就报WslRegisterDistribution failed with error: 0x80370102。这种情况要么升级虚拟化软件,要么在两者之间做取舍。

1.2 ext4.vhdx 为什么会一路膨胀到失控

WSL2 的每个发行版在 Windows 侧都对应一个虚拟磁盘文件ext4.vhdx。Store 版 Ubuntu 的默认位置在:

%LOCALAPPDATA%\Packages\CanonicalGroupLimited.Ubuntu22.04LTS_79rhkp1fndgsc\LocalState\ext4.vhdx

中间那串_79rhkp1fndgsc是包家族名的哈希,不同发行版、不同版本都不一样,最省事的办法是直接在%LOCALAPPDATA%\Packages里搜ext4.vhdx。

关键问题是:这个文件是动态扩展但不自动收缩的。你在 Linux 里rm -rf掉一个 20G 的 conda 环境,Windows 侧的ext4.vhdx一个字都不会小。它只会在你写入新数据时继续变大。所以"我明明删了东西怎么盘还是满的"这种现象,十有八九就是这个原因。

解法有两条路。第一条是用wsl --manage <发行版名> --set-sparse true让它变成稀疏文件,或者用 diskpart 做 compact,把空洞挤出去。第二条、也是更彻底的方案,就是把整个发行版搬到别的盘,以后不会再碰 C 盘。这篇主要讲第二条,第一条放在第 3 章末尾一并说。

2. 安装路径:一条命令走通,以及走不通时的三种绕法

2.1wsl --install背后到底干了哪几件事

Windows 10 2004(内部版本 19041)及以上、Windows 11,用管理员 PowerShell 敲一条命令就够了:

wsl --install

这条命令并不是魔法,它按顺序做了五件事:启用Microsoft-Windows-Subsystem-Linux和VirtualMachinePlatform两个可选功能组件;下载并安装 WSL2 的内核更新包;把 WSL 的默认版本号设为 2;从微软的分发渠道拉取默认发行版(现在是 Ubuntu);最后提示你重启。

想装指定版本就加-d:

wsl --install -d Ubuntu-22.04 wsl --list --online # 先看看有哪些可用 wsl --set-default-version 2 # 单独设置默认版本

如果你是在一台已经有 WSL 的机器上折腾,或者--install因为某些原因走不通,那就手工开功能:

dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

两条都执行完,重启。重启后单独装内核更新包(搜wsl_update_x64.msi),再wsl --set-default-version 2,然后从 Microsoft Store 搜 Ubuntu 点安装。这条路慢一点,但每一步都是可控的,出问题也好定位。

提示:Windows 10 长期服务版(LTSC)用户要注意版本。LTSC 2019 内核版本太低,不支持 WSL2,只能退到 WSL1;LTSC 2021(19044)是支持的,可以放心用。

2.2--list --online超时和--install报 403 的排查顺序

这两个报错在社区里出现频率极高,本质上是同一类问题:命令要去拉微软的发行版清单和安装包,网络这一环卡住了。我一般的排查顺序是这样的,从最轻的改动开始:

  1. 先看系统代理设置有没有残留。设置 → 网络和 Internet → 代理,如果这里还留着某个早就失效的代理地址,wsl.exe会傻乎乎地往那个地址发请求,表现就是超时或者 403。把它关掉,重开一个终端再试,这一步解决过至少三次问题。
  2. 换个命令行的网络出口验证。如果你连手机热点能成功、连公司网络就失败,那说明是本地网络策略在拦,这时候直接走离线路线,别在在线重试上耗时间。
  3. 换 DNS。把网卡的 DNS 手动改成8.8.8.8和114.114.114.114,然后ipconfig /flushdns清一下缓存。有些时候是域名解析被返回了错误结果,导致下载地址压根连不上。
  4. 拆开执行。wsl --install其实可以拆成"开功能 → 装内核 → 装发行版"三步,如果前两步能过、只有第三步拉包失败,那就直接跳到离线导入。

在线安装最头疼的地方在于它不给你断点续传,包下到一半断了就得重来。所以只要失败超过两次,我建议直接放弃在线,走下面这条路。

2.3 离线导入 Ubuntu:最稳的一条路

离线方案的核心思路是:只要拿到一个 Linux 根文件系统的 tar 包,WSL 就能把它变成一个可用的发行版。Ubuntu 官方在cloud-images.ubuntu.com/wsl/下面长期提供 WSL 专用的 rootfs,文件名形如ubuntu-jammy-wsl-amd64-wsl.rootfs.tar.gz,几十兆到一两百兆,用普通下载工具也能拿下。

拿到包之后:

mkdir D:\WSL wsl --import Ubuntu D:\WSL\Ubuntu D:\WSL\ubuntu-jammy-wsl-amd64-wsl.rootfs.tar.gz --version 2

--import三个参数依次是"发行版名字"、"虚拟磁盘存放目录"、"根文件系统包路径"。执行完立刻就能用:

wsl -d Ubuntu

这条路的好处是:不依赖微软的在线分发通道、安装目录你说了算(天生就在 D 盘,省了后面迁移这一步)、tar 包可以留着当备份。坏处是导入进去的默认用户是 root,而且里面只有一个裸系统,没有预装的开发工具。这正好引出后面两章要解决的问题。

注意:从docker export出来的容器 rootfs 也能用--import导进 WSL,但容器镜像往往缺/etc/passwd的完整配置、缺 init 系统,导进去能用但会比较别扭。如果是做开发环境,还是优先用官方 WSL rootfs。

2.4 装完必须验证的四条命令

很多人装完看终端能打开就以为成了,其实有几个信息必须要确认:

wsl -l -v # 列出所有发行版,重点看 VERSION 那一列是不是 2 wsl --status # 看默认发行版、默认版本、内核版本 wsl -d Ubuntu -- uname -a # 看内核,真正的 Linux 内核会带 microsoft-standard-WSL2 字样 wsl -d Ubuntu -- cat /etc/os-release # 确认发行版版本号

wsl -l -v的输出里,STATE 列出现Running说明有实例在跑,Stopped是正常的空闲状态。如果 VERSION 列显示 1,用wsl --set-version Ubuntu 2转过去,转换过程会重新打包文件系统,几个 G 的话大概几分钟。

另外一个小坑:wsl --version这条命令只有从 Microsoft Store 安装的较新版本 WSL 才支持,老的内置版本敲下去会提示"无效命令行选项"。这不代表你装坏了,只是版本老。想要新特性可以用wsl --update升一下。

3. 把发行版整体搬到 D 盘:导出、注销、导入三连

3.1 迁移前必须确认的四件事

迁移这个操作本身不复杂,但它是"注销 + 重建"的过程,中间任何一步出岔子都可能丢数据。所以动手前先过一遍清单:

第一,目标分区空间够不够。整个过程会同时存在三份数据:原来的ext4.vhdx、导出的 tar 包、导入后新生成的ext4.vhdx。所以 D 盘至少要留出原体积的 2.5 倍。原发行版 30G,那就准备 80G 以上宽松点。

第二,先彻底停掉所有实例。wsl --shutdown。这一步不能省,因为如果还有进程在写文件,导出出来的包可能是不一致的状态。执行完可以再敲一次wsl -l -v,确认所有发行版都是 Stopped。

第三,记下发行版的准确名字。wsl -l -v里 NAME 那一列,大小写敏感,Ubuntu和ubuntu不是一回事。后面所有命令都要用这个名字,写错了就是"找不到指定的发行版"。

第四,先想清楚迁移后默认用户会不会变。这一点我踩过坑,放在 3.3 讲。

3.2 导出的具体命令和耗时预估

创建一个工作目录,然后导出:

mkdir D:\WSL wsl --shutdown wsl --export Ubuntu D:\WSL\ubuntu-backup.tar

注意导出格式是.tar,不是.tar.gz,文件体积和原来差不多,不会压缩。如果你的 WSL 版本较新,也可以导出成 VHD 格式:

wsl --export Ubuntu D:\WSL\ubuntu-backup.vhdx --vhd

VHD 格式的好处是能直接在 Windows 上双击挂载查看内容,想抢救文件的时候很方便;缺点是体积更大。日常迁移用 tar 就够了。

耗时方面,我实测的经验值:SSD 上 20G 的发行版大约 3 到 5 分钟,机械硬盘翻倍。导出过程中 PowerShell 是没有进度条的,看起来像卡住了,别急着 Ctrl+C。可以另开一个窗口看目标文件大小是不是在涨。

3.3 注销、导入,以及默认用户为什么会变成 root

导出成功、确认 tar 包大小合理之后,执行:

wsl --unregister Ubuntu wsl --import Ubuntu D:\WSL\Ubuntu D:\WSL\ubuntu-backup.tar --version 2

--unregister会彻底删除原发行版和它的 vhdx,这一步之后 C 盘空间立刻回来了。但也就是从这一刻起,原发行版只存在于那个 tar 包里,所以千万别在导出没验证完之前就 unregister。

导入完成后打开:

wsl -d Ubuntu

你会发现自己变成了 root,提示符是#,whoami返回root。这不是 bug。原因是 WSL 记录"默认登录用户"的地方在 Windows 注册表里,路径是HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss,下面每个发行版一个 GUID 键,键里有个DefaultUid值。--import会生成一个全新的 GUID,DefaultUid默认是 0,也就是 root。原来的那个键随着 unregister 一起没了。

解决方案有两个,第 4 章会详细展开,这里先给最短路径:修/etc/wsl.conf。

cat > /etc/wsl.conf <<'EOF' [user] default=你的用户名 EOF exit

然后在 Windows 侧:

wsl --shutdown wsl

再进去看一眼whoami,应该就是你设置的用户了。

3.4 更省事的--manage --move,以及什么情况下别用它

如果你的 WSL 是从 Microsoft Store 安装的 2.0 以上版本,微软提供了一个原地搬家命令:

wsl --manage Ubuntu --move D:\WSL\Ubuntu

它会直接把 vhdx 移过去并更新注册表路径,不用导出导入,也不用担心默认用户丢失。我一般会先试这条,成功了就省掉整个第 3 章的操作。

但它有两个限制:一是老版本 WSL 不支持,敲下去会说无法识别的参数;二是移动过程中如果目标目录有同名文件或者权限不足,报错信息比较含糊。所以执行前先确认wsl --version能正常输出,且目标目录是空的。

3.5 迁移后的收尾检查与 vhdx 瘦身

搬完之后别急着把 tar 包删掉,先跑一遍检查清单:

wsl -l -v # 确认发行版在,VERSION 是 2 wsl -d Ubuntu -- whoami # 确认默认用户 wsl -d Ubuntu -- ls /mnt/c # 确认 Windows C 盘挂载正常 wsl -d Ubuntu -- df -h # 确认磁盘容量正常

再打开注册表确认路径:HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss,找到对应 GUID,看BasePath是不是指向D:\WSL\Ubuntu\。如果还是旧路径,说明导入的时候参数写错了,需要重新--unregister再来一次。

确认一切正常、跑了一两天没问题之后,tar 包再删。

至于瘦身,如果你的发行版在 C 盘时就已经膨胀得厉害,迁移完可以顺手压一下:

wsl --manage Ubuntu --set-sparse true

或者用 diskpart 这种老派但通用的方式:

wsl --shutdown diskpart # 进入交互后依次输入: # select vdisk file="D:\WSL\Ubuntu\ext4.vhdx" # attach vdisk readonly # compact vdisk # detach vdisk # exit

compact vdisk会把文件系统里已删除数据留下的空洞真正释放掉,一个膨胀到 80G、实际只用了 25G 的 vhdx,压完通常能缩到 30G 出头。这个过程比较慢,几十 G 的话可能要十几分钟。

4. 默认登录账户:为什么改了三处才生效

4.1 WSL 决定"用哪个用户登录"的三层优先级

这是最容易让人困惑的部分,因为它实际上有三个地方都能影响结果:

第一层,命令行参数。wsl -d Ubuntu -u root这种写法优先级最高,一次性的,用完不管。

第二层,/etc/wsl.conf里的[user] default。这是发行版内部的配置,跟着文件系统走,导出导入都会保留。需要wsl --shutdown之后重新进入才生效。

第三层,注册表里的DefaultUid。这是 Windows 侧记录的,由发行版启动器(比如ubuntu2204.exe config --default-user)写入,--import时会重置为 0。

这三者之间,不同 WSL 版本的行为有过细微变化。我在几台机器上实测下来,最稳妥的做法是:wsl.conf和启动器两处都设成同一个用户,别指望某一层单独生效。

4.2/etc/wsl.conf的完整写法和三个细节

先说一个很多人不知道的点:/etc/wsl.conf这个文件不能用 Windows 记事本直接编辑保存。记事本默认会加 UTF-8 BOM 头,而 WSL 解析这个文件时对 BOM 很敏感,可能导致整个文件被忽略、配置完全不生效,而且不报任何错。同理,用 VSCode 从 Windows 侧通过/mnt/c路径去改也要注意编码。

正确做法是进去用 heredoc 或者tee:

sudo tee /etc/wsl.conf > /dev/null <<'EOF' [boot] systemd=true [user] default=dev [automount] enabled = true root = /mnt/ options = "metadata,umask=22,fmask=11" mountFsTab = true [interop] enabled = true appendWindowsPath = false [network] generateResolvConf = true EOF

逐段解释一下为什么这么写:

[boot] systemd=true是让 WSL 用 systemd 作为 init。开了之后systemctl能用,systemctl enable --now docker这类操作才成立。不开的话,服务得靠脚本手动拉。这个开关从 WSL 0.67.6 开始支持,老版本写了也不认。

[user] default=dev就是本节的主角。注意用户名必须真实存在,如果写了一个不存在的用户,WSL 会静默回退到 root,表现就是"我明明配了怎么还是 root",非常容易被误导。

[automount]里的options加了metadata很关键。不加的话,/mnt/c下的文件权限全是一刀切的777,chmod改了没反应。加了之后 Linux 侧才能正确记录权限位。umask=22,fmask=11是让新建文件默认 755/644,比较符合直觉。appendWindowsPath = false是从 PATH 里剔除 Windows 的路径,好处是which python不会莫名其妙指到 Windows 的 Python 上;坏处是code .、explorer.exe这些命令要用全路径。我个人是关掉的,因为 Windows 那堆路径混进 Linux PATH 经常造成版本冲突,是很多"为什么我的 python 是 3.11 但装包装到了 3.9"的根源。

改完之后一定:

wsl --shutdown

然后在 WSL 里whoami验证。

4.3 发行版启动器那条老路:ubuntu.exe config

Store 安装的发行版会附带一个启动器 exe,在%LOCALAPPDATA%\Microsoft\WindowsApps\下面,名字根据发行版不同而不同:ubuntu.exe、ubuntu2204.exe、kali.exe之类。用法:

ubuntu2204.exe config --default-user dev

或者不切目录直接写全路径。这个命令做的事情就是改注册表里那个DefaultUid值。

它的局限在于:只对 Store 安装的发行版有效。如果你的发行版是用wsl --import导进来的,根本不存在这个 exe,敲了就是"不是内部或外部命令"。这时候只能靠wsl.conf。

还有一个隐蔽的坑:如果你在迁移(--import)之前用这条命令设过默认用户,迁移之后这个设置会丢失,因为注册表键被重建了。这就是 3.3 那个"变成 root"问题的另一半原因。

4.4 默认用户彻底丢了的救援流程

假设你导入了一个官方 rootfs,里面只有 root,没有任何普通用户。这时候光改wsl.conf没用,因为你写的那个用户压根不存在。完整流程是:

wsl -d Ubuntu -u root

进去之后:

# 先看看现有用户 cat /etc/passwd | grep -E '/bin/(ba)?sh$' # 用 adduser 创建(比 useradd 更友好,会自动建家目录、拷贝骨架文件) adduser dev # 加进 sudo 组 usermod -aG sudo dev # 确认 id dev

adduser是交互式的,会依次问密码、全名、房间号这些,除了密码其他直接回车跳过即可。它比useradd多做了几件事:创建/home/dev、从/etc/skel复制.bashrc等初始文件、设置默认 shell,这些细节如果漏了,进去之后会发现没有彩色提示符、没有历史记录,很别扭。

然后再写一遍wsl.conf,wsl --shutdown,重进。

注意:给用户改名比新建用户麻烦得多,因为家目录、组、sudoers 里可能都有引用。我一般不会去改已有用户的用户名,不够折腾的。

5. root 密码与 sudo 权限:最容易想当然的两个地方

5.1sudo passwd root之后,为什么"登录"还是失败

Ubuntu 的 WSL 发行版默认把 root 账户锁着,passwd -S root会显示一个L(locked)。首次启动创建普通用户之后,root 是没有密码的。要解锁:

sudo passwd root

输入新密码两次,root 就解锁了。但很多人做完这一步,会去试"用 root 登录",然后遇到各种"密码错误"。这里面有几个不同的原因,得分开看。

第一种情况,你敲的是su但输错了密码。su从普通用户切到 root,需要的是 root 密码(刚设的那个),不是你的 sudo 密码。很多人脑子里两个密码混着,试三次就锁了。

第二种情况,你在某个客户端的"登录用户"选项里切不到 root。比如某些 Windows 侧的终端工具、SFTP 客户端提供"以 root 连接"的选项,但走的是 SSH,而 WSL 里 SSH 服务默认根本没启动,而且 sshd 默认配置里PermitRootLogin通常是prohibit-password。这不是密码的问题,是服务压根没开。

第三种情况,密码里带了特殊字符,或者在输入法状态下敲的。这个听起来很低级,但我见过好几次,尤其是密码里带@、#这类符号,中文输入法的全角符号和半角符号看起来几乎一样。

在 WSL 环境下,最可靠的"以 root 身份进去"的方式根本不是密码,而是命令行直通:

wsl -d Ubuntu -u root

这条命令不需要任何密码,直接给你一个 root shell。这是 WSL 相对物理机最大的便利,也是最好的应急通道。想想物理服务器上 root 密码忘了有多麻烦,WSL 里一句命令解决。

5.2 忘了 sudo 密码怎么办(两分钟解决)

顺着上一节说。如果你只是忘了自己那个普通用户的密码,导致sudo用不了:

wsl -d Ubuntu -u root

进去之后:

passwd dev # 重置普通用户密码 passwd -S dev # 看状态,P 表示有密码可用 exit

不用重启,不用wsl --shutdown,退出后立刻生效。这个流程我一年要用上两三次,都是帮同事弄的。

5.3 sudo 权限的判定链,以及"加了组为什么没生效"

sudo能不能用,走的是一条链,任何一环断了都不行:

  1. 用户是否在sudo组里(Debian/Ubuntu 系的约定;如果是 RHEL 系发行版,组名是wheel,配置也不同)
  2. /etc/sudoers里是否有%sudo ALL=(ALL:ALL) ALL这一行
  3. 用户的组变更是否已经生效

第一条:

sudo usermod -aG sudo dev

注意-aG里的a不能丢,-G单独用是"把这个用户的附加组设置为指定组",会覆盖掉原有附加组。丢了a的后果是用户可能失去其他所有附加组权限。

第二条:如果/etc/sudoers里的%sudo那行被注释掉了或者被人改坏了,那加组也没用。用visudo检查:

sudo visudo

它会做语法校验,写完保存时如果有语法错误会拒绝保存,这个设计就是为了防止你把 sudoers 改坏导致彻底锁死。

第三条是最容易踩的坑:Linux 里用户的组成员关系是在登录时确定的,usermod -aG改完之后,当前这个 shell 会话里是不会生效的。groups命令看不到新组,sudo也还是不能用。解决办法有两个:

# 方案一:临时刷新当前会话的组 newgrp sudo # 方案二:退出重进(推荐,彻底) exit

我见过有人加完组立刻敲sudo发现不行,以为命令写错了,反复加了好几遍,其实就是没重登。

验证:

groups dev sudo -l # 列出当前用户可以用 sudo 执行什么

sudo -l会要求输一次密码,然后列出权限规则。如果输出里有(ALL : ALL) ALL,说明权限完整。

5.4 免密 sudo:什么场景值得开

WSL 里有个很实用的场景是免密 sudo:写自动化脚本、跑 CI、装 Docker 的时候,卡在交互式密码输入上很烦。配法是在/etc/sudoers.d/下放一个独立文件:

sudo tee /etc/sudoers.d/dev > /dev/null <<'EOF' dev ALL=(ALL) NOPASSWD:ALL EOF sudo chmod 0440 /etc/sudoers.d/dev sudo chown root:root /etc/sudoers.d/dev

三个细节必须注意:

  • 文件权限必须是0440。sudo 会检查 sudoers.d 下所有文件的权限,如果不是 0440 或者属主不是 root,会直接忽略甚至报错。
  • 文件名不要带点号,也不要以~结尾。sudo在加载/etc/sudoers.d/时会跳过包含.或~的文件名,这是防止编辑器留下的临时文件被误加载。我就见过有人把文件命名为dev.conf,然后死活不生效。
  • 不要直接改主 sudoers 文件。用 drop-in 文件的好处是,出问题时删掉这一个文件就恢复了。

提示:免密 sudo 在个人开发机上图省事可以开,但同样的配置绝对不能带到任何多人使用的服务器上。另外,如果你后面要装 Docker 并把用户加进 docker 组,那要意识到 docker 组的权限实质上等价于 root(能挂载宿主机文件系统),这是另一个层面的安全边界问题,不在本文讨论范围。

5.5 常见报错对照表

把这一章遇到的典型报错整理成一张表,出问题的时候直接对号入座:

报错现象根本原因处理方式
dev is not in the sudoers file不在 sudo 组,或组变更未生效usermod -aG sudo dev后退出重进
sudo: /etc/sudoers is world writablesudoers 权限被改坏wsl -u root进去chmod 0440 /etc/sudoers
su: Authentication failureroot 未设密码,或输错密码sudo passwd root
输入密码时屏幕无任何反馈正常行为,不是卡死盲打后回车
passwd: Authentication token manipulation error/etc/shadow权限异常或文件系统只读wsl -u root进去检查ls -l /etc/shadow
Sorry, user dev is not allowed to execute ...sudoers 里写了限定命令列表检查/etc/sudoers.d/下的规则
sudoers 改坏导致完全无法 sudo语法错误wsl -d Ubuntu -u root走应急通道修复
wsl -u root也进不去,报 0x8007019eWSL 可选功能没启用回到第 2 章重新开功能

这张表里最后一行的思路值得强调:只要wsl -d <发行版> -u root还能用,WSL 里就没有救不回来的配置问题。这个 root shell 相当于物理机的单用户模式或者 PE 环境,是最后一道保险。

6. 装完之后的日常:VSCode 联动、字体观感与几个省心配置

6.1 VSCode 连 WSL 的正确姿势,以及为什么你的项目要放 Linux 侧

VSCode 连 WSL 靠的是官方 "WSL" 扩展(包含在 Remote Development 扩展包里)。装完之后有两种连接方式:

一种是从 WSL 终端里发起:

cd ~/projects/myapp code .

第一次会自动在 WSL 里下载并安装vscode-server,装到~/.vscode-server目录下,有一定体积。之后 VSCode 会在 Windows 侧开一个窗口,但所有编辑器后端进程都在 WSL 里跑,插件也装在 Linux 侧。

另一种是从 VSCode 左下角的绿色角标点进去,选 "Connect to WSL"。

这里有个性能问题必须讲清楚:项目文件放在 Linux 文件系统(比如~/projects/)和放在/mnt/c/...下,性能差距是数量级的。原因是后者每次文件读写都要经过 9P 协议从 Linux 转发到 Windows,inotify文件监听更惨,热重载、npm run dev、vite这类工具会出现几秒甚至十几秒的延迟。我做过对比,同一个前端项目,node_modules安装放在/mnt/c下耗时是 Linux 侧的 4 到 6 倍。

所以我的习惯是:WSL 里建一个~/projects,所有需要跑构建的项目放这里。如果因为某些原因必须用 Windows 侧的文件(比如要跟 Windows 上的工具共享),那就接受慢,或者用rsync做单向同步。

顺带说几个 WSL 里做开发常用的环境准备,都有各自的坑:

  • Docker:装 Docker Desktop 并打开 "Use WSL 2 based engine",然后在设置里勾选要集成的发行版;或者直接在 WSL 里装docker.io并开 systemd。前者省事,后者更轻。
  • Redis:sudo apt install redis-server,注意要开 systemd 才能systemctl start redis,否则得手动redis-server --daemonize yes。
  • CUDA:WSL2 支持 CUDA,但装的是 Linux 版驱动不用装,只要 Windows 侧驱动够新,WSL 里nvidia-smi就能看到卡。装错版本(在 WSL 里装 Windows 驱动)是最常见的错误。
  • binwalk这类工具:WSL2 下正常工作,WSL1 下某些依赖内核特性的功能会失败,这也是前面推荐 WSL2 的原因之一。

6.2 字体和观感:怎么调出接近 macOS 的终端体验

这个话题在社区里讨论得很多。macOS 终端好看,其实是几个因素叠加:高分屏 + 优秀的抗锯齿策略 + 字体本身的字形设计 + 合适的行高和字距。Windows 上要接近,得一项一项调。

先说字体选择。等宽字体里我个人常用的几个:

字体特点适合谁
JetBrains Mono字形方正,连字丰富,辨识度高通用首选
Cascadia Code / Next微软官方,Windows Terminal 默认图省事
Maple Mono中英混排处理得好,圆润经常写中文注释
Fira Code连字鼻祖,生态成熟老用户
Sarasa Mono SC(更纱黑体)中文等宽,中英对齐中文重度用户

中英混排的终端里,如果只用纯西文等宽字体,中文会回退到系统默认字体,出现"中文字比英文宽一倍、行高被撑开"的割裂感。解决办法就是选一个原生支持中文等宽的字体,比如更纱黑体,然后把它放在字体列表的后面作为 fallback。

VSCode 里的设置:

{ "terminal.integrated.fontFamily": "'JetBrains Mono', 'Sarasa Mono SC', monospace", "terminal.integrated.fontSize": 14, "terminal.integrated.lineHeight": 1.3, "terminal.integrated.letterSpacing": 0.2, "terminal.integrated.fontWeight": 400, "terminal.integrated.fontLigatures": true, "terminal.integrated.gpuAcceleration": "on", "editor.fontFamily": "'JetBrains Mono', 'Sarasa Mono SC', monospace", "editor.fontLigatures": true, "editor.fontSize": 14 }

几个参数的作用:lineHeight调到 1.2 到 1.4 之间,行距一开整个界面立刻松快起来,这是最接近 macOS 观感的一步。letterSpacing加 0.2 到 0.5,字不会挤在一起。gpuAcceleration开启用 GPU 渲染,滚动明显更顺。

Windows Terminal 这边(如果你用它而不是 VSCode 内置终端),在settings.json的 profiles.defaults 里:

{ "profiles": { "defaults": { "font": { "face": "JetBrainsMono Nerd Font", "size": 11, "features": { "calt": 1, "liga": 1 } }, "antialiasingMode": "grayscale", "padding": "10, 10, 10, 10" } } }

antialiasingMode这个设置是观感差异的关键。Windows 默认用 ClearType(次像素抗锯齿),字会带一点点彩色边缘,锐利但略显毛糙;改成grayscale之后,字体边缘变柔和平滑,视觉上非常接近 macOS 的渲染风格。代价是在低 DPI 屏幕上会略微发虚。1440p 以上的屏幕我建议直接上grayscale,试一次就知道差别。

如果你想要 powerline 那种带箭头和图标的分隔符(配 oh-my-zsh、starship 提示符),字体名要选带 "Nerd Font" 后缀的版本,比如JetBrainsMono Nerd Font。普通版字体里没有那些字形,会显示成方框。

6.3.wslconfig:控制 WSL 吃多少内存

WSL2 的内存占用是很多人抱怨的点:跑着跑着任务管理器里 Vmmem 进程吃到十几 G。这是虚拟机的正常行为,Linux 内核会把空闲内存当缓存用,不会主动归还。有两个控制手段。

一是在 Windows 侧的用户目录建.wslconfig(注意是全局的,放在C:\Users\你的用户名\.wslconfig):

[wsl2] memory=8GB processors=4 swap=2GB localhostForwarding=true

这个文件管的是整个 WSL2 虚拟机的资源上限,和发行版内部的/etc/wsl.conf是两回事,别搞混。改完wsl --shutdown生效。

二是定期wsl --shutdown。这个命令会彻底关掉虚拟机,内存立刻归还给 Windows。我一般在跑完大编译、或者准备玩游戏之前敲一下。

processors别设太大,设成和物理核心数一样有时候反而慢,因为 Windows 侧还要用。一般设成物理核心数的一半到三分之二比较舒服。

6.4 备份习惯和彻底卸载的顺序

最后说两个运维层面的习惯。

备份:我现在的做法是每个月或者每次做重大环境变更(比如升级 Python 大版本、装完 CUDA)之前,导出一份快照:

wsl --shutdown wsl --export Ubuntu D:\WSL\backup\ubuntu-20250101.tar

几十 G 的空间换一份安心,比出问题时从头配环境划算太多。文件按日期命名,保留最近两三份就够。

卸载:如果哪天要彻底清掉,顺序很重要,别搞反。

wsl --unregister Ubuntu # 第一步,删掉发行版和 vhdx,数据不可恢复 wsl --shutdown

然后从"设置 → 应用"里卸载对应的发行版应用(如果有的话)。再进"启用或关闭 Windows 功能",取消勾选适用于 Linux 的 Windows 子系统和虚拟机平台。最后别忘了去D:\WSL\或者%LOCALAPPDATA%\Packages\下面看一眼,有没有残留的ext4.vhdx没删干净——Store 版发行版有时候卸载了应用但 vhdx 还留着,白白占几十 G。

我个人用下来最省心的几条经验

这套流程我在自己机器和同事的机器上前后跑过十几次,有几个反复验证过的结论。

迁移这件事,能先用wsl --manage --move就别用导出导入。导出导入虽然通用,但每次都要处理默认用户丢失、注册表路径、tar 包临时占用这几件事,而--move一条命令解决。只有 WSL 版本太老或者--move报错的时候才走导出导入这条路。

遇到任何"命令行进不去""发行版状态怪怪的""改了配置不生效"的问题,第一反应永远是:

wsl --shutdown

再重进。八成的怪问题都是实例状态没刷新,或者在某个窗口里还挂着一个后台进程。这一招比看日志快得多。

最后,/etc/wsl.conf和.wslconfig这两个文件我建议你在装好系统的当天就配好,别等到出问题再回头补。尤其[automount] options里的metadata和[interop] appendWindowsPath这两项,早配早省心,晚了等 PATH 里混进 Windows 的一堆路径、pip install装到了 Windows 的 Python 上,排查起来能烦死人。文件都用 heredoc 或者tee写,别碰记事本,这一条我踩过一次,配了半天不生效,最后发现是 BOM 头,气得够呛。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 1:40:28

游戏行业术语表:从肉鸽到DAU,听懂行话才能融入圈子

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 1:39:36

Neutralinojs实战:轻量桌面壳搭建、运行与打包全攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 1:39:17

手写C语言词法分析器:基于DFA的工业级实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 1:38:01

YOLOv5+OpenCV实现表格结构识别与Excel导出

简介&#xff1a;本资源是一个面向本科毕业设计与课程设计的深度学习实战项目&#xff0c;聚焦表格图像的结构识别与关键信息提取&#xff0c;适用于计算机视觉初学者及AI方向课程作业开发者。项目基于YOLO目标检测框架实现端到端表格行列定位与内容解析&#xff0c;解决传统OC…

作者头像 李华
网站建设 2026/10/1 1:37:53

PyTorch虚拟试衣源码实战:人体解析、形变与合成全链路解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华