前言:以为搞定了,结果还是翻车
上一篇我花了半天把 Windows Terminal 默认 Shell 从 PowerShell 5.1 换成了 7.x,配好 UTF-8 Profile,自我感觉良好。
然后今天用 Codex CLI 读一个中文 Markdown 文件,输出直接炸了:
text
�ҵ��ĵ�...
我当时的心情:我不是已经全切到 7 了吗?
排查:终端是 7,但工具跑的是 5
先确认当前环境:
powershell
$PSVersionTable.PSVersion
text
Major Minor Patch
----- ----- -----
7 6 1
是 PowerShell 7,没错。
然后我直接在 pwsh 里用 Get-Content 读那个中文文件:
powershell
Get-Content ultimate-architecture-zh.md
中文完美显示,一行乱码都没有。
那问题出在哪?
我打开任务管理器,在 Codex CLI 执行命令的时候看进程------
它调用的不是 pwsh.exe,是 powershell.exe。
text
C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe
这就是 Windows 自带的 PowerShell 5.1。
真相:工具有自己的"默认 Shell"
很多 CLI 工具、IDE 插件、CI/CD 任务,它们在背后跑命令时,不会用你 Windows Terminal 里设置的那个 Shell。
它们会去系统里找 powershell.exe,而这个指向的永远是那个老旧的 5.1。
所以你的情况是:
| 你在哪操作 | 实际用的是 | 编码行为 |
|---|---|---|
| Windows Terminal 手动开 | pwsh.exe 7.x | UTF-8,正常 |
| VS Code 终端手动开 | pwsh.exe 7.x | UTF-8,正常 |
| Codex CLI 自动执行命令 | powershell.exe 5.1 | 系统 ANSI(GBK),乱码 |
你换的只是"你手动打开的终端",工具链里藏着一个隐性旧版,你从来没换过它。
为什么会乱码?原理拆解
那个中文文件,我用十六进制查了文件头:
text
23 20 48 6F ...
23 是 #,20 是空格,48 6F 是 Ho。这是标准的 UTF-8 无 BOM 编码,文件本身完全正确。
但 Windows PowerShell 5.1 的 Get-Content 有个坑:
默认编码是 -Encoding Default,也就是系统 ANSI 代码页。
在中文 Windows 上,ANSI 代码页是 GBK(936)。用 GBK 去读 UTF-8 文件,中文字节序列对不上,出来就是乱码。
而我之前配的 Profile 是给 PowerShell 7 写的,里面只有这些:
powershell
[Console]::OutputEncoding = $utf8
$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
$PSDefaultParameterValues['Set-Content:Encoding'] = 'utf8'
$PSDefaultParameterValues['Add-Content:Encoding'] = 'utf8'
这四条只影响 输出 ,不影响 读取。
-
Out-File→ 写文件 -
Set-Content→ 写文件 -
Add-Content→ 追加写文件
唯独漏了 Get-Content(读文件)。
所以当 Codex CLI 在后台用 PowerShell 5.1 跑 Get-Content 中文文件.md 时,它走了默认编码 GBK,读 UTF-8 文件,直接乱码。
解决:一行代码的事
方案一:临时解决(每次手写参数)
以后读中文文件时显式加 -Encoding UTF8:
powershell
Get-Content -Encoding UTF8 文件.md
但这治标不治本,工具链里自动跑的命令你没法改。
方案二:根本解决(补上 Profile 缺失的那一行)
给 PowerShell 5.1 的 Profile 也补上 Get-Content 的默认 UTF-8 设置。
你的 PS5 Profile 路径是:
text
C:\Users\a1\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
在里面加这一行:
powershell
$PSDefaultParameterValues['Get-Content:Encoding'] = 'utf8'
加上之后,你现有的 Profile 内容应该长这样:
powershell
$utf8 = [System.Text.UTF8Encoding]::new($false)
[Console]::InputEncoding = $utf8
[Console]::OutputEncoding = $utf8
$OutputEncoding = $utf8
# 这些你之前已经有了
$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
$PSDefaultParameterValues['Set-Content:Encoding'] = 'utf8'
$PSDefaultParameterValues['Add-Content:Encoding'] = 'utf8'
# 补上这一行 ↓
$PSDefaultParameterValues['Get-Content:Encoding'] = 'utf8'
保存,重启终端。之后所有在 PowerShell 5.1 里跑的 Get-Content,不管是谁调用的,都会默认按 UTF-8 读。
这次踩坑的核心教训
1. "换了默认终端" ≠ "所有工具都用新版本"
你改的是 Windows Terminal 的默认 Profile,只影响你 手动打开的终端窗口。
系统里那个 powershell.exe(5.1)永远在,任何硬编码调用它的工具都会继续用旧版。
2. Profile 的四件套要齐全
很多人配 UTF-8 只配了输出,漏了输入。完整的"读写编"覆盖应该是:
| 命令 | 方向 | 对应参数默认值 |
|---|---|---|
Get-Content |
读文件 | $PSDefaultParameterValues['Get-Content:Encoding'] |
Set-Content |
写文件 | $PSDefaultParameterValues['Set-Content:Encoding'] |
Out-File |
写文件 | $PSDefaultParameterValues['Out-File:Encoding'] |
Add-Content |
追加写 | $PSDefaultParameterValues['Add-Content:Encoding'] |
少一个都不行。
3. 排查此类问题的通用流程
以后遇到"终端里正常,工具里乱码",按这个顺序排查:
-
确认文件编码(hex 查看文件头)
-
确认工具实际调用的 Shell(任务管理器看进程)
-
确认该 Shell 版本的默认编码行为
-
检查 Profile 是否覆盖了对应 cmdlet 的默认参数
结尾
这次的问题用一句话总结:
你换了前门的锁,但工具走的是后门,后门还是那把旧锁。
加上 Get-Content 那一行之后,Codex CLI 跑中文文件完全正常了。如果你也用类似的 AI CLI 工具、IDE 插件或自动化脚本,建议检查一下它们到底调的是哪个 Shell,说不定你也正踩在这个坑里。