终端中文乱码需系统locale、终端UTF-8解码、含CJK字形字体三者严格对齐;缺一即现????、测试或□,且须确认zh_CN.utf8已生成、LC_ALL未覆盖、终端字体本地加载。

终端中文显示乱码,**不是改个 LANG 就能解决的**。真正起作用的是系统 locale、终端解码方式、中文字体三者必须同时对齐为 UTF-8 且含 CJK 字形;漏掉任意一环,就会出现 ????、测试 或 □。
确认系统是否真有 zh_CN.UTF-8 这个 locale
很多人执行 export LANG=zh_CN.UTF-8 后没效果,是因为系统压根没生成这个 locale —— 它不是“设了就有”,而是得先让 glibc 知道它存在。
- 运行
locale -a | grep zh_CN,如果输出为空或只有zh_CN.GB18030,说明还没生成 - Debian/Ubuntu:编辑
/etc/locale.gen,取消注释zh_CN.UTF-8 UTF-8,再执行sudo locale-gen - RHEL/CentOS/Fedora:执行
sudo localedef -c -i zh_CN -f UTF-8 zh_CN.UTF-8(注意-c参数不能省,否则静默失败) - 再跑一次
locale -a | grep zh_CN,确认看到的是zh_CN.utf8(小写 utf8,带点号)——后续export时必须严格匹配这个名称
LC_ALL 优先级最高,会覆盖所有其他 locale 设置
LC_ALL 是开关型变量:只要它非空,LANG 和所有 LC_* 都会被无视。很多脚本或服务(比如 cron、systemd unit)里硬编码了 LC_ALL=C,会导致终端里明明 locale 看着正常,实际程序仍按 ASCII 处理中文。
- 排查时先运行
locale,重点看LC_ALL是否为空;如果不为空,临时执行unset LC_ALL测试 - 检查
~/.bashrc或~/.zshrc里有没有export LC_ALL=C或类似硬编码 - 只对交互式 shell 生效:推荐在
~/.zshrc末尾加两行:export LANG=zh_CN.UTF-8和export LC_ALL=zh_CN.UTF-8,然后source ~/.zshrc - 别改
/etc/environment或/etc/profile—— 这会让非交互式服务也继承,可能引发日志解析失败、grep匹配异常等问题
终端模拟器自身必须设为 UTF-8 解码,且字体要含中文字形
即使 locale 全对,终端若用 GBK 去解码 UTF-8 字节流,照样显示 测试;而如果字体不支持中文,就只会显示 □。
- GNOME Terminal:菜单 → Preferences → Profile → Text → Character encoding → 选
Unicode (UTF-8) - Windows Terminal(连 WSL 或 SSH):设置 JSON 中加
"locale": "zh_CN.UTF-8",并确保"fontFace"是含 CJK 字形的字体(如Cascadia Code PL、Noto Sans CJK SC) - PuTTY / Xshell / FinalShell:进 Translation 或字符编码设置页,把
Remote character set明确设为UTF-8,不是 “Use font encoding” 或 “Auto” - 验证字体:运行
fc-list :lang=zh,有输出才说明系统已加载中文字体;没输出就装fonts-noto-cjk(Debian/Ubuntu)或google-noto-cjk(RHEL/Fedora)
最容易被忽略的是:远程连接时,服务器装了字体、locale 也对了,但客户端终端没配字体 —— 渲染发生在本地,服务器字体根本用不上。还有就是 tmux 里中文变下划线,大概率是它检测到客户端声称不支持 UTF-8,得在 tmux 配置里加 set -g default-terminal "screen-256color" 并确保 $TERM 正确。











