
WSL装完之后的第三个月我猜你浏览器收藏夹里躺着至少五篇标题差不多的文章都叫“WSL常用命令”。可真到要用的那天还是得重新搜一遍发行版怎么从C盘挪到D盘、端口为什么Windows访问不到、明明关了终端内存怎么还占着几个G。问题不在于命令少而在于这些命令背后的机制没串起来导致每次遇到问题都得从零开始查。这篇东西想把WSL的常用命令按“你实际会遇到什么场景”重新排一遍而不是按字母顺序罗列。从Windows侧调度的wsl.exe、发行版内部的Linux命令、两侧文件互访、网络转发、两个配置文件的取舍一直到磁盘瘦身和故障排查尽量把每条命令“为什么是这个、什么时候该用它、用错了会怎样”讲透。适合已经装过WSL、日常在用但总觉得使不上劲的人完全没接触过的也能看懂因为关键概念我都会先铺垫。1. 先分清你敲的是wsl.exe还是Linux命令1.1 两条命令体系为什么容易混刚上手时最常见的困惑是不知道某条命令该在PowerShell里敲还是在WSL终端里敲。原因很简单WSL实际上由两层东西组成一层是Windows这边的管理程序wsl.exe负责创建、启停、导入导出虚拟机另一层是发行版内部那个真实的Linux环境里面有bash、apt、systemctl。前者在PowerShell或CMD里执行后者必须先进WSL终端。判断方法很直接命令里带双横线长参数、并且以wsl开头基本就是Windows侧的管理命令以sudo、apt、systemctl、cd / 开头的是Linux侧。有个容易踩的点是在WSL终端里敲wsl开头的命令其实也能跑因为Windows的PATH被拼接进了Linux环境变量但这时候你调用的是Windows的exe路径换算、权限模型全都不一样很容易出现莫名其妙的行为。我的习惯是管理类操作一律开PowerShell日常开发一律在WSL终端两边不混着来。1.2 wsl --status与wsl --version排障第一步该看哪个遇到任何异常先敲这两条。wsl --status给的是当前默认发行版、默认版本号、内核版本信息偏“状态”wsl --version输出的是WSL程序本身、内核、WSLg、系统版本的完整版本号矩阵信息偏“版本”。wsl --status wsl --version很多人只记得第一条。实际上当你遇到“明明装了新版但行为还是老样子”这类问题时--version才有用因为它能告诉你WSL本体是不是Store版本、内核是不是最新。老版本Windows上wsl --version会直接报“无效参数”这本身就是一条重要信息说明你的WSL还是比较早期的内置版本很多新特性比如镜像网络模式、systemd支持根本不存在别在旧版本上折腾新配置。提示如果wsl --version提示参数无效先去执行wsl --update更新完再回来看。这条判断能省掉大量无效搜索。1.3 用wsl -l -v建立一张“发行版地图”wsl -l -v完整写法wsl --list --verbose是我用得最频繁的一条没有之一。wsl -l -v输出三列NAME、STATE、VERSION。NAME是发行版名字STATE分Running和StoppedVERSION是1或2。这张表的价值在于后面几乎所有命令的-d参数都要填这里的NAME而且名字是区分大小写的但很多人从开始菜单里看到的名字和实际NAME并不一致比如显示成“Ubuntu”实际NAME可能是“Ubuntu-22.04”。另一个细节是STATE这一列会骗人。有时候显示Running但实际上没有任何终端窗口开着那多半是有后台进程挂着比如某个服务或者一个没退出的nohup任务。反过来显示Stopped也不代表完全没占资源虚拟机会在后台保留一段时间才真正释放。想确认虚拟机的真实开销看任务管理器里的Vmmem或者“虚拟机平台”相关进程更准。2. 发行版的增删改查安装、切换、注销与搬家2.1 wsl --install背后的完整动作链新版Windows上一条wsl --install就能装完但这条命令实际干了一串事启用“适用于Linux的Windows子系统”和“虚拟机平台”两个可选功能、下载并安装WSL内核更新包、把WSL2设为默认版本、拉取一个默认发行版并触发首次初始化。知道这个链条出问题时才知道该看哪一环。wsl --install wsl --install -d Ubuntu-22.04 wsl --install --no-launch-d指定发行版--no-launch表示装完不自动打开终端适合批量配置。想看有哪些可装的发行版用wsl --list --online不过这个列表依赖网络公司网络受限时经常拉不下来这时候别以为是命令坏了。最常见的失败场景是装完提示重启重启后打开终端发现还是老版本或者直接报错。原因通常是虚拟化没开。判断方法是在任务管理器“性能”页看CPU的“虚拟化”是不是“已启用”如果是“已禁用”任何WSL2命令都不会成功得先进固件设置打开。这一步卡住的人非常多而且报错信息往往很含糊只说“请启用虚拟机平台”不会直接告诉你固件里的开关。2.2 --set-default-version与--set-version的区别这两条命令长得像作用完全不同混用会导致“我明明设了2怎么还是1”。wsl --set-default-version 2 wsl --set-version Ubuntu-22.04 2前者改的是以后新装发行版的默认版本对已经存在的发行版毫无影响。后者才是把某个已存在的发行版从1转成2。很多人只敲了第一条然后发现老的发行版还是VERSION 1白折腾半天。转换过程会真的做一次文件系统迁移耗时取决于数据量几十G的话十几分钟很正常中途别关窗口。转换完成后建议进去检查一下网络和文件权限因为WSL1和WSL2的模型差别很大WSL1是系统调用翻译层和Windows共享网络栈和文件系统访问/mnt/c非常快WSL2是真正的轻量虚拟机有独立内核和网络跨文件系统访问反而慢。这个差异后面第4节会展开。注意转换不可逆地“降级”回去虽然有命令支持但经常留下权限和软链接问题做之前先导出备份具体步骤见2.3。2.3 wsl --export/--import把整个发行版装进一个tar这是WSL里最被低估的一组命令。导出后你得到的是一个tar文件里面是完整的根文件系统。wsl --export Ubuntu-22.04 D:\backup\ubuntu-2204.tar wsl --import Ubuntu-Dev D:\wsl\ubuntu-dev D:\backup\ubuntu-2204.tar --version 2第一行导出第二行导入成一个叫Ubuntu-Dev的新发行版放在D盘。这套组合能干三件事备份、迁移到非系统盘、复制一份做实验环境。我个人的习惯是每次大版本升级前导一次占用几十G但省心。有几个坑必须提前说。第一导入后的发行版默认用户会变成root不是原来的用户因为/etc/wsl.conf里的默认用户配置在某些导入路径下不会自动生效需要手动进wsl.conf补上或者用wsl --import之后立刻wsl -d Ubuntu-Dev -u root进去改。第二导入语法里的三个位置参数顺序是“名字、安装目录、tar文件”中间那个目录必须是空目录或者不存在的目录指向一个已有内容的目录会直接失败。第三tar文件不含.wslconfig这类Windows侧配置跨机器迁移时那部分得手动带走。还有一个不太为人知的--import-in-place它不复制文件而是直接把一个已有的ext4格式vhdx注册成发行版适合你已经有了磁盘镜像的情况。它要求源文件必须是ext4用错了会报格式错误别拿普通tar去试。2.4 --unregister之前必须做的三件事wsl --unregister 名字会把这个发行版连同它的虚拟磁盘文件一起删除不可恢复不进回收站。wsl --unregister Ubuntu-Dev执行前建议按顺序确认三件事先wsl -l -v确认名字没打错差一个字符可能删掉另一个再确认这个发行版里没有你要留的数据尤其是家目录下的代码和数据库文件最后确认已经导出过备份或者数据在Git远端有。我见过不止一次有人想删测试环境结果手滑删了主力开发环境重装容易但里面那堆配置好的环境得重来一遍。删完磁盘空间不会立刻回来因为vhdx文件虽然被删了但如果之前有别的发行版共享了某些缓存空间回收还有延迟。真正的空间回收看第7节。3. 生命周期控制启动、终止、关闭的那点门道3.1 wsl -d与wsl --exec指定发行版和指定命令默认发行版只有一个但机器上往往装了好几个。-d用来指定进哪个--exec用来不进入交互式shell直接执行一条命令然后退出。wsl -d Ubuntu-22.04 wsl -d Ubuntu-22.04 --exec ls -la /home wsl -d Ubuntu-22.04 -u root--exec和直接跟命令的区别在于--exec不经过shell不加载bashrc速度更快脚本里调用很合适直接跟命令则会被shell解释环境变量和别名都生效。写自动化脚本时用--exec更可控因为它不会因为某个人在bashrc里加了奇怪的echo而污染输出。-u指定用户这个在导入的发行版上特别有用因为默认用户是root你可以用-u 你的用户名临时切回去验证。如果忘了原来有哪些用户进root后cat /etc/passwd看一眼UID大于等于1000的基本就是普通用户。3.2 --terminate和--shutdown的真实差异这两条经常被当成同义词其实粒度不同。wsl --terminate Ubuntu-22.04 wsl --shutdown--terminate只停指定的那一个发行版其他发行版和它们共享的虚拟机不受影响。--shutdown则是把整个WSL虚拟机包括所有发行版、WSLg、相关后台组件一起关掉。什么时候用哪个很清楚只想重启某一个环境用terminate改了.wslconfig里的内存或CPU配置、或者要瘦身磁盘、或者遇到资源占用异常必须用shutdown因为配置文件是虚拟机级别的不彻底关掉不会重新读取。有个细节值得注意--terminate之后立刻再进去虚拟机的内存开销并不会马上降下来因为Vmmem进程的回收有延迟。想要立刻看到效果还是得--shutdown。3.3 后台进程为什么会莫名其妙消失很多人遇到过在WSL里起了个服务关掉终端窗口过一会儿再进来服务没了。这不是bug是设计。WSL的虚拟机会在所有交互式会话结束后一段时间自动关闭里面的所有进程随之终止。应对办法有三条路。一是保持一个终端窗口开着最土但最有效。二是用Windows任务计划程序在登录时执行wsl -d 发行版 --exec 你的启动脚本让它在后台常驻。三是在较新版本里配置systemd见6.3把服务交给systemd管理但注意这并不能阻止虚拟机整体关闭只是让服务在虚拟机存活期间更规范。真正要长期跑的东西老实说WSL不是最佳载体它更适合开发调试。如果确实需要常驻建议在Windows侧用计划任务兜底虚拟机被关掉后能被重新拉起来。4. Windows与Linux两侧的文件互访4.1 /mnt/c的9P性能坑有多深WSL2里访问Windows文件是通过/mnt/c这类挂载点底层走的是9P协议。这条路径的IO性能比原生Linux文件系统差一个数量级尤其是在大量小文件场景下比如npm install、git status、编译一个中等规模的项目。实测下来同样的项目放在/mnt/c/Users/xxx/project和放在WSL自己的家目录~/project安装依赖的时间能差三到五倍有时候更多。原因是每次文件操作都要跨虚拟化边界做协议转换开销累积起来非常可观。所以有一条经验值得记住代码放Linux侧资料放Windows侧。项目代码、依赖目录、数据库文件都放在WSL根文件系统里文档、图片、下载的东西放Windows盘需要时通过/mnt/c读一下就行这类操作对性能不敏感。从Windows侧访问WSL文件路径是\\wsl.localhost\发行版名\老版本是\\wsl$\。这个路径可以直接在资源管理器地址栏敲也可以映射成网络驱动器。但它同样慢别拿它做大文件批量操作。4.2 wslpath路径转换的正确写法手工把C:\Users\xxx\a.txt改成/mnt/c/Users/xxx/a.txt容易出错尤其是路径里有空格、中文或者盘符不是C的时候。wslpath专门干这个。wslpath -u C:\Users\test\a.txt # Windows 转 Linux wslpath -w /home/test/a.txt # Linux 转 Windows wslpath -a C:\temp # 转成绝对路径-u是unix-w是windows-a是absolute。写脚本时这三个参数非常有用比如你要把当前目录传给Windows侧的程序notepad.exe $(wslpath -w ./config.yaml)注意引号别省路径里有空格时不加引号会直接截断。另外wslpath只做字符串转换不检查文件是否存在路径拼错了它照样给你转所以转换完最好再ls一下确认。4.3 explorer.exe .、cmd.exe、clip.exe的跨界调用WSL的一大便利是能直接调用Windows的可执行文件因为Windows的PATH被拼进了Linux环境变量。几个高频用法explorer.exe . # 用资源管理器打开当前Linux目录 cmd.exe /c start . # 另一种打开方式 clip.exe file.txt # 把文件内容塞进Windows剪贴板 powershell.exe -c Get-Date cat file.txt | clip.exeexplorer.exe .大概是我用得最多的因为在图形界面里看目录结构比ls -R直观太多。但有个小坑如果当前路径含特殊字符或者过长explorer可能打不开这时候先用pwd看一眼路径是否正常。调用Windows程序时注意两点。一是返回值语义不同Windows程序的退出码和Linux习惯不完全一致脚本里判断要小心。二是路径必须是Windows格式传/home/xxx过去它是不认的得用wslpath -w转一下。4.4 元数据与权限chmod在/mnt/c下为什么失灵在/mnt/c下执行chmod x script.sh然后ls -l一看权限没变这是最常见的困惑之一。原因是Windows的NTFS文件系统没有POSIX权限位WSL默认用一套固定映射所有文件都显示成755或644。解决办法是在/etc/wsl.conf里打开metadata[automount] enabled true options metadata,umask22,fmask11改完必须wsl --shutdown再进。打开之后chmod才会真正生效代价是每次文件操作多一层属性读写/mnt/c的IO会再慢一点点。另一个相关问题是换行符。Windows文件用CRLFLinux脚本用LF在/mnt/c下编辑过的shell脚本拿到Linux侧执行经常报bad interpreter。处理办法是用dos2unix批量转或者在编辑器里把默认换行符设成LF。这个坑极其隐蔽报错信息完全不提换行符新手往往查半天。5. WSL2网络localhost转发与端口排查5.1 为什么WSL里的服务Windows能直接访问在WSL里起一个监听8080的服务Windows的浏览器直接访问localhost:8080就能通这看起来理所当然其实是WSL2做了一层端口转发。它会在Windows侧监听同样的端口把流量转到虚拟机内部。这层转发大部分时候工作良好但有几个前提服务必须监听在0.0.0.0或者::如果只监听127.0.0.1转发可能失效端口不能被Windows侧的其他程序占用防火墙策略不能拦截。一旦不满足表现就是“服务明明起着浏览器就是打不开”。排查顺序建议这样走先在WSL里curl localhost:8080确认服务本身没问题再在Windows PowerShell里Test-NetConnection -ComputerName localhost -Port 8080看端口通不通最后查netstat -ano | findstr :8080看是谁在监听。这三步能定位绝大部分问题。5.2 反过来访问Windows服务该用什么地址WSL访问Windows上跑的服务不能用localhost因为那指向的是WSL自己。要用Windows宿主机的IP。传统做法是从/etc/resolv.conf里取nameserver那通常就是宿主机地址cat /etc/resolv.conf | grep nameserver ip route show | grep default更稳的写法是直接读默认网关export WIN_HOST$(ip route show default | awk {print $3}) curl http://$WIN_HOST:3000但这个IP在每次重启后可能变化所以别把IP写死在配置里。写脚本时动态取或者在新版本里启用镜像网络模式见5.4那样localhost就能双向互通省掉这一堆麻烦。5.3 端口占用排查的完整链路“端口冲突”在WSL里比在纯Linux里复杂因为涉及两个系统。完整链路是这样的第一步在WSL里确认服务状态和监听地址ss -tlnp | grep 端口。如果显示127.0.0.1:8080而不是0.0.0.0:8080那Windows访问不到就是正常的改服务的监听配置。第二步在Windows侧看端口是否被占netstat -ano | findstr :8080拿到PID后用tasklist | findstr PID看是什么进程。有时候是上一次没退干净的WSL转发进程。第三步如果两边都正常但还是不通检查防火墙。Windows Defender对入站连接有默认拦截第一次访问时可能弹过提示而被点了拒绝这个拒绝规则会一直留着得去防火墙设置里手动删掉。第四步极端情况下是WSL虚拟机的网络栈出了问题wsl --shutdown重启一次往往能解决。这就是为什么排障时重启永远是性价比最高的一步。5.4 镜像网络模式能解决什么问题较新版本的WSL支持把网络模式改成镜像改完之后WSL和Windows共享同一套网络接口localhost双向直接通IPv6支持更好也不再需要记宿主机IP。在C:\Users\你的用户名\.wslconfig里加[wsl2] networkingModemirrored改完wsl --shutdown重启。效果是访问Windows服务直接用localhost端口转发的那堆毛病基本消失。代价是这个模式相对新个别老版本上的行为还不够稳定比如某些依赖特定网卡枚举的工具可能识别异常。生产环境谨慎个人开发值得一试。6. 两个配置文件.wslconfig与wsl.conf6.1 作用域区分谁管虚拟机谁管发行版这两个文件名差一个点位置和作用完全不同混了会改半天没反应。文件位置作用范围生效方式.wslconfigWindows用户目录如C:\Users\xxx\.wslconfig整个WSL虚拟机wsl --shutdown后重进wsl.conf发行版内部/etc/wsl.conf单个发行版wsl --terminate 发行版名后重进判断该改哪个很简单涉及内存、CPU、网络模式、内核参数改.wslconfig涉及默认用户、挂载选项、是否加载Windows PATH、是否启用systemd改wsl.conf。我见过有人把[boot] systemdtrue写进.wslconfig然后纳闷为什么不生效就是作用域搞反了。6.2 内存与CPU限制的实际效果WSL2默认会占用宿主机最多一半的内存虚拟机启动后即使空闲Vmmem进程也可能吃掉好几个G。在内存紧张的机器上这个默认值需要调。[wsl2] memory8GB processors4 swap2GBmemory是上限不是预留正常不会一直占满但Linux的页缓存会倾向于用满可用内存所以看起来占用很高。这个问题在新版本的autoMemoryReclaim出现后缓解了不少[experimental] autoMemoryReclaimgradual sparseVhdtrueautoMemoryReclaim会在空闲时把缓存还给WindowssparseVhd让虚拟磁盘文件能自动收缩。这两个都算实验特性但从实际体验看比手动瘦身省事得多。设多少合适我的经验是8G内存的机器给4G16G给8G32G以上给12到16G。给太多反而会因为页缓存膨胀导致Windows侧吃紧。改完记得wsl --shutdown不然配置不生效这是最常见的“改了没用”原因。6.3 systemd开启的条件与代价默认情况下WSL里没有systemdsystemctl命令会报错。较新版本支持开启[boot] systemdtrue前提是WSL版本足够新大约0.67.6之后老版本上写这段配置不会报错但也不会有任何效果属于“静默失败”很坑。判断方法还是wsl --version看版本号。开启之后的好处是能用systemctl管理服务很多依赖systemd的软件比如某些数据库、容器工具能正常安装。代价是启动变慢内存开销增加因为systemd本身要拉起一批单元。而且开启后某些老的服务脚本可能和新初始化系统冲突。我的建议是需要就跑不需要就别开。判断标准很实在装软件时如果它报“systemd not running”那就开如果一路顺利没必要为了“更正统”而开。6.4 interop与appendWindowsPath的取舍wsl.conf里有两个和互操作相关的开关很多人不知道它们的存在但确实影响体验。[interop] enabled true appendWindowsPath trueappendWindowsPath默认是true把Windows的PATH拼接到Linux的PATH里好处是能直接敲code、explorer.exe、notepad.exe。坏处是PATH变得很长某些脚本在遍历PATH时性能受影响更麻烦的是命令冲突Windows侧和Linux侧有同名程序时可能调用到错的那个。如果遇到“明明装了某个Linux工具敲出来却是Windows版本”的怪事就是这个原因。解决办法是把它设成false然后需要的Windows程序用绝对路径或者在.bashrc里手动alias几个常用的。我现在的做法是保留true但注意顺序Linux侧的命令在前面冲突时优先走Linux版本。7. 磁盘空间、备份与故障排查7.1 vhdx只涨不缩的原因与瘦身步骤WSL2的磁盘是一个叫ext4.vhdx的虚拟磁盘文件它只会变大不会自动变小。你在里面删了20G文件Windows侧看这个文件还是原来的大小。这是设计使然不是bug。瘦身分两步。先彻底关掉WSLwsl --shutdown然后用diskpart压缩。先找到vhdx路径通常在C:\Users\用户名\AppData\Local\Packages\发行版包名\LocalState\ext4.vhdx或者你导入时自定义的目录。然后diskpart select vdisk fileC:\路径\ext4.vhdx attach vdisk readonly compact vdisk detach vdisk exit顺序不能乱必须是只读挂载才能压缩否则会失败。整个过程可能几分钟取决于文件大小和磁盘速度。压缩前建议先导出备份虽然这个操作本身很安全但磁盘操作向来没有绝对保险。如果嫌麻烦直接用前面提到的sparseVhdtrue让系统自己处理代价是磁盘碎片可能多一点。我个人是平时用sparseVhd半年手动压一次。7.2 迁移发行版到非系统盘的完整流程C盘紧张时最常见的需求。步骤是导出、注销、导入三步缺一不可wsl --export Ubuntu-22.04 D:\wsl\backup.tar wsl --unregister Ubuntu-22.04 wsl --import Ubuntu-22.04 D:\wsl\ubuntu D:\wsl\backup.tar --version 2导入后记得改默认用户否则进去是root# 在 WSL 内执行 sudo tee /etc/wsl.conf EOF [user] default你的用户名 EOF然后用wsl --terminate Ubuntu-22.04重启生效。确认一切正常后再删掉那个tar文件别急着手快万一导入出问题它就是你唯一的退路。还有一种更省事的思路一开始就别装在C盘。新版wsl --install支持--location参数指定安装位置装的时候就避开系统盘后面省去迁移的麻烦。这个参数在不同版本上的支持情况不完全一样装之前先wsl --help看一眼有没有。7.3 起不来时的排查顺序遇到WSL完全打不开按这个顺序走能快速定位第一步wsl --status看有没有输出。如果直接报错通常是WSL功能本身没启用去“启用或关闭Windows功能”里确认“适用于Linux的Windows子系统”和“虚拟机平台”都勾上了。第二步确认虚拟化是否开启任务管理器性能页看CPU的虚拟化状态。没开的话任何WSL2命令都会失败得进固件设置。第三步wsl --update更新内核。很多“突然用不了”的情况都是系统更新后内核不匹配更新一次就好。第四步看具体发行版能不能单独起来wsl -d 发行版名。如果报“找不到指定的文件”多半是vhdx被移动或删除了用wsl -l -v确认路径。第五步如果还是不行wsl --shutdown之后重启机器。听起来很土但WSL的虚拟机状态确实偶尔会卡住重启是最快恢复的手段。真要救不回来还有导出备份这条路。只要vhdx文件还在即使注册信息坏了也能用--import-in-place重新挂回来数据不会丢。所以平时养成定期导出的习惯比任何排障技巧都管用。7.4 一个可持续的日常维护习惯折腾了这么多次我最后固化下来一套很简单的维护节奏分享出来参考。每周做一次wsl --shutdown让虚拟机和配置彻底重载一次能规避很多“越用越怪”的问题。每月检查一次wsl -l -v把不用的发行版--unregister掉别让一堆测试环境在那儿占空间。每季度导出一次主力发行版放在非系统盘文件大但心里踏实。系统重大更新之后先跑一遍wsl --update和wsl --status确认环境正常再继续干活。这套习惯看起来琐碎但比起某天早上发现环境起不来、花一整天重装的代价还是划算太多。WSL这东西平时很稳一旦出问题往往就是全盘性的提前留退路是唯一靠谱的应对。最后再分享一个小技巧把常用的几条命令写成PowerShell函数放进profile比如一个wslrestart做shutdown再进默认发行版一个wslbk做带时间戳的导出。省下的不是敲键盘的时间是不用每次回忆参数拼写的心力。工具用得顺手前提永远是你知道它在背后做了什么。