元数据
| id | wsl-pipe-encoding | 收录 | 2026-08-29 |
|---|---|---|---|
| 问题域 | 编码代理与终端 | 主题分组 | 容器与 WSL |
| 适用工具 | wsl · 外部工具 | ||
症状
PowerShell(5.1 和 7)里调用 `wsl.exe ...` 时输出乱码:
```
w s l : �hKm0R ... # 每个字符中间有空格(UTF-16LE 的 00 字节被当字符显示)
wsl --help | more # 每字符一行([microsoft/WSL#13093](https://github.com/microsoft/WSL/issues/13093) 官方 issue)
中文内容变成 � 一类替换符
```
特征:**直接** `wsl echo hi > 文件`(cmd 重定向)字节正常(UTF-8);
坏的是**管道/捕获**场景:PowerShell 脚本赋值、CI 抓取、`|` 管道;
WSL 启动时还会混入一段代理检测横幅(stderr),加剧观感。
原因
wsl.exe 在管道/非 TTY 场景输出 **UTF-16LE(无 BOM)**,PowerShell 捕获后按自己的 stdout 编码
(实测 PS 5.1 与 pwsh 7 的 -Command 链路都是 UTF-16LE 无 BOM)写到下游;
下游按 UTF-8/单字节解码 → 每个 ASCII 字符被 00 隔开,中文全变 �。
这是 wsl.exe 的已知行为,2025 年的 #13093(WSL 2.5.7)仍存在。
解法
1. **脚本里设 `$env:WSL_UTF8 = "1"`** 再调 wsl(微软官方开关,实测 pwsh -File 下 wsl 输出变 UTF-8 正常);
不想改全局就放在脚本开头,或临时 `cmd /c "set WSL_UTF8=1 && wsl ..."`。
2. **复杂/长命令别硬拼命令行**(转义、长度都会炸):把脚本写到 WSL 内文件再执行:
`wsl bash /tmp/x.sh`;PowerShell 写文件走 UNC:`Set-Content \\wsl.localhost\Ubuntu\tmp\x.sh`。
3. **超长/特殊字符用 base64 传输**:`wsl bash -lc "echo <base64> | base64 -d | bash"`(实测通过,绕开引号/转义/长度三坑)。
4. **输出走文件**:让 wsl 内命令把结果写 `/tmp/out.txt`,再用 `Get-Content \\wsl.localhost\Ubuntu\tmp\out.txt` 读——
UTF-8 文件直读无编码问题,比管道可靠。
5. 辅助手段:`[Console]::OutputEncoding = [Text.Encoding]::UTF8` 影响 PowerShell 写控制台编码,可配合 1 使用。
6. WSL 启动横幅("检测到 localhost 代理配置...")是 stderr 噪声:设了 WSL_UTF8 后不乱码,仍介意可忽略或加 `2>$null`。
验证证据
- 本地实测(2026-08-29,Windows 11 + WSL Ubuntu,PowerShell 5.1 与 pwsh 7):
- 对照:cmd 直调 `wsl.exe echo hi > 文件` → 字节 `68 69 0A`(UTF-8,正常);
- 复现:`pwsh -NoProfile -Command "wsl echo hi" > 文件` → 字节 `77 00 73 00 6C 00 ...`(UTF-16LE 无 BOM),
下游按 UTF-8 显示即 "w s l :" 乱码——与本条目开头截图同款,#13093 同款;PowerShell 5.1 同样复现;
- 修复:ps1 里 `$env:WSL_UTF8="1"` 后 `& wsl.exe echo hi` → 字节 `77 73 6C 3A 20 E6 A3 80`(UTF-8 正常,中文不丢);
- base64 通道:`wsl bash -lc "echo dGVzdA== | base64 -d"` → test(exit 0);
- 文件中转:WSL 内写 /tmp/out.txt 后 UNC 读取,无编码问题(实践天天在用)。
- 实测复现日志(2026-08-29)
来源与证据
素材来源:https://github.com/microsoft/WSL/issues/13093
验证证据:Evidence details kept locally (2026-08-29)