【2026-3-10官方已修复该问题,此贴终结】尝试解决 ClaudeCode在Windows环境下copy乱码问题
- 内容介绍
- 文章标签
- 相关推荐
起因
本来只是个小bug,不影响使用,但是最近写文档还挺多的,这个功能对我比较实用
问题描述
Claude Code 的 /copy 命令在 Windows(包括 WSL)上复制含中文、日文、韩文、越南语等非 ASCII 字符的文本时,粘贴结果为乱码(mojibake)。macOS 和 Linux 用户不受此问题影响。
相关 Issue: #22346(OPEN, stale)、#27709(closed as duplicate)
测试环境: Windows 10/11, Claude Code v2.1.x, pwsh 7
为什么会产生这个问题?
Claude Code 在不同平台使用不同的剪贴板命令(cli.js 中定义):
{
macos: ["pbcopy"], // ✅ 原生支持 UTF-8
linux: ["xclip -selection clipboard", "wl-copy"], // ✅ 原生支持 UTF-8
wsl: ["clip.exe"], // ❌ 不支持 UTF-8
windows: ["clip"], // ❌ 不支持 UTF-8
}
当用户执行 /copy 时,执行链路如下:
用户在 pwsh 中运行 claude (Node.js 进程)
│
├─ /copy 触发剪贴板写入
│
├─ Node.js 调用 execa("clip", { input: text, shell: true })
│ │
│ ├─ Node.js 内部将 JavaScript 字符串 (UTF-16) 转为 UTF-8 字节流
│ │ 写入子进程的 stdin
│ │
│ └─ shell: true → 使用 process.env.comSpec (= cmd.exe)
│ │
│ └─ 实际执行: cmd.exe /d /s /c "clip"
│ │
│ └─ clip.exe 从 stdin 读取字节流
│ │
│ └─ ❌ clip.exe 使用系统 OEM 代码页 (如 CP437/CP936)
│ 解读字节流,而非 UTF-8
│
└─ 结果:UTF-8 字节被按错误编码解读 → 乱码
核心矛盾:
| 环节 | 编码 |
|---|---|
| Node.js stdin 输出 | UTF-8 |
| clip.exe stdin 读取 | 系统 OEM 代码页(GetOEMCP(),通常为 CP437 或 CP936) |
这个编码不匹配是乱码的直接原因。
为什么不能通过 ~/.bashrc 或 $PROFILE 修复?
我们测试了以下方案,均无法解决此问题:
在 ~/.bashrc 中设置 chcp 65001
.bashrc 只在 Claude Code 的 Bash Tool(执行 shell 命令的工具)调用时被 source。而 /copy 是 Node.js 进程直接 spawn cmd.exe 子进程,完全不经过 bash:
/copy 的路径:Node.js → cmd.exe → clip.exe (不经过 bash)
Bash Tool: Node.js → bash (source .bashrc) (跟 /copy 无关)
在 PowerShell $PROFILE 中设置 chcp 65001
chcp 65001 改变的是当前 console 会话的代码页,但 clip.exe 读取 stdin 时使用的是系统 OEM 代码页(通过 GetOEMCP() 获取),这是系统级全局设置,chcp 无法改变它。
那为什么
chcp 65001 >nul & clip在同一个 cmd 会话里就能工作?因为
chcp 65001在同一个cmd.exe会话中同时改变了该进程的 stdin 处理方式。clip.exe作为同一会话的下一个命令直接执行时,继承了这个修改。但从外部(pwsh、bash)设置的 codepage 无法传递到 Node.js 随后 spawn 的新cmd.exe进程中。
PowerShell $input | Set-Clipboard
PowerShell 的 $input 自动变量从 stdin 读取时,同样不使用 UTF-8 编码,即使在 pwsh 7 中也是如此。经 Node.js 模拟测试验证,结果仍为乱码。
解决方案
以下提供两种修复方案,任选其一即可。
方案一:补丁脚本(推荐)
直接修改 cli.js 中的剪贴板命令,在调用 clip 前先用 chcp 65001 切换到 UTF-8 代码页。
优点: 最精准,只改一个字符串,零副作用,不影响系统中任何其他软件
缺点: 每次 Claude Code 更新后需重新执行
使用方法
- 将下方脚本保存为
fix-claude-copy.mjs - 执行补丁:
node fix-claude-copy.mjs
- 重启 Claude Code 即可生效
补丁内容
脚本会自动定位 cli.js 并做以下替换:
# Windows
windows:["clip"] → windows:["chcp 65001 >nul & clip"]
# WSL
wsl:["clip.exe"] → wsl:["cmd.exe /c 'chcp 65001 >nul & clip'"]
完整脚本代码
#!/usr/bin/env node
/**
* Claude Code /copy 中文乱码修复补丁
*
* 问题: Windows/WSL 上 /copy 命令使用 clip.exe,不支持 UTF-8 stdin,导致中文乱码
* 修复: 在调用 clip 之前先用 chcp 65001 切换到 UTF-8 代码页
*
* 用法: node fix-claude-copy.mjs
* 每次 Claude Code 更新后需重新执行
*/
import { readFileSync, writeFileSync } from 'fs';
import { execSync } from 'child_process';
import { join } from 'path';
// 定位 cli.js
let cliPath;
try {
const prefix = execSync('npm config get prefix', { encoding: 'utf-8' }).trim();
cliPath = join(prefix, 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js');
readFileSync(cliPath);
} catch {
const home = process.env.USERPROFILE || process.env.HOME;
const candidates = [
// Windows (npm global)
join(home, 'AppData', 'Roaming', 'npm', 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js'),
// Linux / WSL (npm global)
'/usr/lib/node_modules/@anthropic-ai/claude-code/cli.js',
'/usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js',
];
cliPath = null;
for (const p of candidates) {
try { readFileSync(p); cliPath = p; break; } catch { continue; }
}
}
if (!cliPath) {
console.error('❌ 找不到 Claude Code cli.js,请确认已全局安装 @anthropic-ai/claude-code');
process.exit(1);
}
console.log(`📂 cli.js: ${cliPath}`);
const patches = [
{ name: 'Windows', original: 'windows:["clip"]', patched: 'windows:["chcp 65001 >nul & clip"]' },
{ name: 'WSL', original: 'wsl:["clip.exe"]', patched: `wsl:["cmd.exe /c 'chcp 65001 >nul & clip'"]` },
];
let content = readFileSync(cliPath, 'utf-8');
let changed = false;
for (const p of patches) {
if (content.includes(p.patched)) {
console.log(`✅ ${p.name} 补丁已存在`);
} else if (content.includes(p.original)) {
content = content.replace(p.original, p.patched);
changed = true;
console.log(`🔧 ${p.name} 补丁已应用: ${p.original} → ${p.patched}`);
} else {
console.warn(`⚠️ ${p.name} 未找到原始字符串,可能 cli.js 结构已变更`);
}
}
if (changed) {
writeFileSync(cliPath, content, 'utf-8');
console.log('\n✅ 补丁完成!重启 Claude Code 即可生效');
} else {
console.log('\n✅ 无需修改');
}
console.log('\n💡 提示: 每次 Claude Code 更新后需重新运行此脚本');
方案二:clip.cmd 包装器 + PATH 拦截
创建一个 clip.cmd 包装器,通过 PATH 优先级让系统先找到它而不是原始的 clip.exe。
优点: 不修改 cli.js,Claude Code 更新后无需重新操作
缺点: 需要修改 PATH 环境变量,该 pwsh 会话内所有调用 clip 的程序都会走包装器(实际影响极小,因为几乎没有其他程序通过命令行调用 clip.exe)
注意: 此方案仅适用于 Windows 原生环境,不适用于 WSL。WSL 用户请使用方案一。
使用方法
第一步:创建包装器
在你的用户目录下创建 ~/clip-fix/clip.cmd(路径可自定义),内容如下:
@echo off
chcp 65001 >nul
C:\Windows\System32\clip.exe
第二步:修改 PowerShell/BASH 配置
编辑你的 PowerShell 配置文件($PROFILE),在末尾添加:
# Fix: Claude Code /copy 中文乱码补丁
$env:PATH = "$HOME\clip-fix;$env:PATH"
感谢佬友的补充,
【2026-3-10官方已修复该问题,此贴终结】尝试解决 ClaudeCode在Windows环境下/copy乱码问题 开发调优git-bash启动的cc得这样 .bashrc export PATH="$HOME/clip-fix:$PATH"
第三步:重启 PowerShell 并启动 Claude Code
新开一个 pwsh 窗口即可生效。
原理说明
原本 PATH 搜索顺序:
... → C:\Windows\System32\clip.exe ← 系统原版(不支持 UTF-8)
修改后:
... → ~\clip-fix\clip.cmd ← 包装器(先被找到,切换代码页后再调用真正的 clip.exe)
... → C:\Windows\System32\clip.exe ← 不会被执行到
关于 utf8clip
感谢哈雷酱推荐了 bluemarsh/utf8clip 这个项目。它的思路是对的——用 .NET 以 UTF-8 读取 stdin,再通过 Windows API 写入剪贴板,和我们的修复方向一致。
但它不能直接用于解决这个问题,原因是:
- 命令名不同: utf8clip 安装后的命令是
utf8clip,而 Claude Code 硬编码调用的是clip。即使装了 utf8clip,Claude Code 依然会调用系统的clip.exe,根本不会走到 utf8clip,如果要替换仍然需要做一个包装器或改名——又回到了 PATH 拦截的套路 - 额外依赖: 需要 .NET Core 3.0+ 运行时
--【壹】--:
我自己电脑也是alias了一个魔改的,但是要发出来还是要考虑最用户使用环境的最小侵入
--【贰】--:
git-bash启动的cc得这样
.bashrc
export PATH="$HOME/clip-fix:$PATH"
--【叁】--:
用鼠标选择文字后自动复制乱码,如果选择完,按Ctrl+C复制,再粘贴就不乱码了
--【肆】--:
我是在Teminal用的,鼠标选文字不会自动复制,感谢佬友提供这个情况,这也太离谱了
--【伍】--:
image595×271 16.3 KB
没有命令 我 cc 版本是 2.1.63 CC 插件也是 2.1.63
image352×176 30.2 KB
--【陆】--:
2.1.59 增加的
--【柒】--:
感谢回复
--【捌】--: phaseddd:
命令名不同: utf8clip 安装后的命令是
utf8clip,而 Claude Code 硬编码调用的是clip。即使装了 utf8clip,Claude Code 依然会调用系统的clip.exe,根本不会走到 utf8clip,如果要替换仍然需要做一个包装器或改名——又回到了 PATH 拦截的套路
.bashrc
alias clip="utf8clip"
需要 .NET Core 3.0+ 运行时
我直接丢到 Claude.ai 上让他给我拉 utf8clip 仓库 转写成 rust
而且正则patch匹配那个容易吃瘪 还是AST解析匹配好些 我群里不是发的有模板来着
--【玖】--:
好吧, 我不用 cli 已经好几个月了
--【拾】--:
image1257×660 68.7 KB
/copy和直接从回复里面手动复制都会
--【拾壹】--:
嗯 ?还有回归问题?
--【拾贰】--:
这两者是完全不同的TUI模式
加这个或者不加的话
操作能力也不一样
我们都是不加的那种旧式的
--【拾叁】--:
感谢佬友补充,已更新主贴
--【拾肆】--:
我也碰到了,而且直接复制内容去粘贴也会乱码,我放假看看
--【拾伍】--:
今天更新2.1.91后,又出现了乱码问题 呜呼
--【拾陆】--: 哈雷彗星:
AST 解析匹配
触及到俺知识盲区了,我晚上再去磨一磨
--【拾柒】--:
CLAUDE_CODE_NO_FLICKER=1
我是加上这个配置后,再复制或者/export都乱码,去掉就不乱码
--【拾捌】--:
当然只有cli有
--【拾玖】--:
我都没理解, 有 /copy 这个命令吗 我的CC 怎么没提示
这是自定义命令吗 还是自身的命令?
起因
本来只是个小bug,不影响使用,但是最近写文档还挺多的,这个功能对我比较实用
问题描述
Claude Code 的 /copy 命令在 Windows(包括 WSL)上复制含中文、日文、韩文、越南语等非 ASCII 字符的文本时,粘贴结果为乱码(mojibake)。macOS 和 Linux 用户不受此问题影响。
相关 Issue: #22346(OPEN, stale)、#27709(closed as duplicate)
测试环境: Windows 10/11, Claude Code v2.1.x, pwsh 7
为什么会产生这个问题?
Claude Code 在不同平台使用不同的剪贴板命令(cli.js 中定义):
{
macos: ["pbcopy"], // ✅ 原生支持 UTF-8
linux: ["xclip -selection clipboard", "wl-copy"], // ✅ 原生支持 UTF-8
wsl: ["clip.exe"], // ❌ 不支持 UTF-8
windows: ["clip"], // ❌ 不支持 UTF-8
}
当用户执行 /copy 时,执行链路如下:
用户在 pwsh 中运行 claude (Node.js 进程)
│
├─ /copy 触发剪贴板写入
│
├─ Node.js 调用 execa("clip", { input: text, shell: true })
│ │
│ ├─ Node.js 内部将 JavaScript 字符串 (UTF-16) 转为 UTF-8 字节流
│ │ 写入子进程的 stdin
│ │
│ └─ shell: true → 使用 process.env.comSpec (= cmd.exe)
│ │
│ └─ 实际执行: cmd.exe /d /s /c "clip"
│ │
│ └─ clip.exe 从 stdin 读取字节流
│ │
│ └─ ❌ clip.exe 使用系统 OEM 代码页 (如 CP437/CP936)
│ 解读字节流,而非 UTF-8
│
└─ 结果:UTF-8 字节被按错误编码解读 → 乱码
核心矛盾:
| 环节 | 编码 |
|---|---|
| Node.js stdin 输出 | UTF-8 |
| clip.exe stdin 读取 | 系统 OEM 代码页(GetOEMCP(),通常为 CP437 或 CP936) |
这个编码不匹配是乱码的直接原因。
为什么不能通过 ~/.bashrc 或 $PROFILE 修复?
我们测试了以下方案,均无法解决此问题:
在 ~/.bashrc 中设置 chcp 65001
.bashrc 只在 Claude Code 的 Bash Tool(执行 shell 命令的工具)调用时被 source。而 /copy 是 Node.js 进程直接 spawn cmd.exe 子进程,完全不经过 bash:
/copy 的路径:Node.js → cmd.exe → clip.exe (不经过 bash)
Bash Tool: Node.js → bash (source .bashrc) (跟 /copy 无关)
在 PowerShell $PROFILE 中设置 chcp 65001
chcp 65001 改变的是当前 console 会话的代码页,但 clip.exe 读取 stdin 时使用的是系统 OEM 代码页(通过 GetOEMCP() 获取),这是系统级全局设置,chcp 无法改变它。
那为什么
chcp 65001 >nul & clip在同一个 cmd 会话里就能工作?因为
chcp 65001在同一个cmd.exe会话中同时改变了该进程的 stdin 处理方式。clip.exe作为同一会话的下一个命令直接执行时,继承了这个修改。但从外部(pwsh、bash)设置的 codepage 无法传递到 Node.js 随后 spawn 的新cmd.exe进程中。
PowerShell $input | Set-Clipboard
PowerShell 的 $input 自动变量从 stdin 读取时,同样不使用 UTF-8 编码,即使在 pwsh 7 中也是如此。经 Node.js 模拟测试验证,结果仍为乱码。
解决方案
以下提供两种修复方案,任选其一即可。
方案一:补丁脚本(推荐)
直接修改 cli.js 中的剪贴板命令,在调用 clip 前先用 chcp 65001 切换到 UTF-8 代码页。
优点: 最精准,只改一个字符串,零副作用,不影响系统中任何其他软件
缺点: 每次 Claude Code 更新后需重新执行
使用方法
- 将下方脚本保存为
fix-claude-copy.mjs - 执行补丁:
node fix-claude-copy.mjs
- 重启 Claude Code 即可生效
补丁内容
脚本会自动定位 cli.js 并做以下替换:
# Windows
windows:["clip"] → windows:["chcp 65001 >nul & clip"]
# WSL
wsl:["clip.exe"] → wsl:["cmd.exe /c 'chcp 65001 >nul & clip'"]
完整脚本代码
#!/usr/bin/env node
/**
* Claude Code /copy 中文乱码修复补丁
*
* 问题: Windows/WSL 上 /copy 命令使用 clip.exe,不支持 UTF-8 stdin,导致中文乱码
* 修复: 在调用 clip 之前先用 chcp 65001 切换到 UTF-8 代码页
*
* 用法: node fix-claude-copy.mjs
* 每次 Claude Code 更新后需重新执行
*/
import { readFileSync, writeFileSync } from 'fs';
import { execSync } from 'child_process';
import { join } from 'path';
// 定位 cli.js
let cliPath;
try {
const prefix = execSync('npm config get prefix', { encoding: 'utf-8' }).trim();
cliPath = join(prefix, 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js');
readFileSync(cliPath);
} catch {
const home = process.env.USERPROFILE || process.env.HOME;
const candidates = [
// Windows (npm global)
join(home, 'AppData', 'Roaming', 'npm', 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js'),
// Linux / WSL (npm global)
'/usr/lib/node_modules/@anthropic-ai/claude-code/cli.js',
'/usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js',
];
cliPath = null;
for (const p of candidates) {
try { readFileSync(p); cliPath = p; break; } catch { continue; }
}
}
if (!cliPath) {
console.error('❌ 找不到 Claude Code cli.js,请确认已全局安装 @anthropic-ai/claude-code');
process.exit(1);
}
console.log(`📂 cli.js: ${cliPath}`);
const patches = [
{ name: 'Windows', original: 'windows:["clip"]', patched: 'windows:["chcp 65001 >nul & clip"]' },
{ name: 'WSL', original: 'wsl:["clip.exe"]', patched: `wsl:["cmd.exe /c 'chcp 65001 >nul & clip'"]` },
];
let content = readFileSync(cliPath, 'utf-8');
let changed = false;
for (const p of patches) {
if (content.includes(p.patched)) {
console.log(`✅ ${p.name} 补丁已存在`);
} else if (content.includes(p.original)) {
content = content.replace(p.original, p.patched);
changed = true;
console.log(`🔧 ${p.name} 补丁已应用: ${p.original} → ${p.patched}`);
} else {
console.warn(`⚠️ ${p.name} 未找到原始字符串,可能 cli.js 结构已变更`);
}
}
if (changed) {
writeFileSync(cliPath, content, 'utf-8');
console.log('\n✅ 补丁完成!重启 Claude Code 即可生效');
} else {
console.log('\n✅ 无需修改');
}
console.log('\n💡 提示: 每次 Claude Code 更新后需重新运行此脚本');
方案二:clip.cmd 包装器 + PATH 拦截
创建一个 clip.cmd 包装器,通过 PATH 优先级让系统先找到它而不是原始的 clip.exe。
优点: 不修改 cli.js,Claude Code 更新后无需重新操作
缺点: 需要修改 PATH 环境变量,该 pwsh 会话内所有调用 clip 的程序都会走包装器(实际影响极小,因为几乎没有其他程序通过命令行调用 clip.exe)
注意: 此方案仅适用于 Windows 原生环境,不适用于 WSL。WSL 用户请使用方案一。
使用方法
第一步:创建包装器
在你的用户目录下创建 ~/clip-fix/clip.cmd(路径可自定义),内容如下:
@echo off
chcp 65001 >nul
C:\Windows\System32\clip.exe
第二步:修改 PowerShell/BASH 配置
编辑你的 PowerShell 配置文件($PROFILE),在末尾添加:
# Fix: Claude Code /copy 中文乱码补丁
$env:PATH = "$HOME\clip-fix;$env:PATH"
感谢佬友的补充,
【2026-3-10官方已修复该问题,此贴终结】尝试解决 ClaudeCode在Windows环境下/copy乱码问题 开发调优git-bash启动的cc得这样 .bashrc export PATH="$HOME/clip-fix:$PATH"
第三步:重启 PowerShell 并启动 Claude Code
新开一个 pwsh 窗口即可生效。
原理说明
原本 PATH 搜索顺序:
... → C:\Windows\System32\clip.exe ← 系统原版(不支持 UTF-8)
修改后:
... → ~\clip-fix\clip.cmd ← 包装器(先被找到,切换代码页后再调用真正的 clip.exe)
... → C:\Windows\System32\clip.exe ← 不会被执行到
关于 utf8clip
感谢哈雷酱推荐了 bluemarsh/utf8clip 这个项目。它的思路是对的——用 .NET 以 UTF-8 读取 stdin,再通过 Windows API 写入剪贴板,和我们的修复方向一致。
但它不能直接用于解决这个问题,原因是:
- 命令名不同: utf8clip 安装后的命令是
utf8clip,而 Claude Code 硬编码调用的是clip。即使装了 utf8clip,Claude Code 依然会调用系统的clip.exe,根本不会走到 utf8clip,如果要替换仍然需要做一个包装器或改名——又回到了 PATH 拦截的套路 - 额外依赖: 需要 .NET Core 3.0+ 运行时
--【壹】--:
我自己电脑也是alias了一个魔改的,但是要发出来还是要考虑最用户使用环境的最小侵入
--【贰】--:
git-bash启动的cc得这样
.bashrc
export PATH="$HOME/clip-fix:$PATH"
--【叁】--:
用鼠标选择文字后自动复制乱码,如果选择完,按Ctrl+C复制,再粘贴就不乱码了
--【肆】--:
我是在Teminal用的,鼠标选文字不会自动复制,感谢佬友提供这个情况,这也太离谱了
--【伍】--:
image595×271 16.3 KB
没有命令 我 cc 版本是 2.1.63 CC 插件也是 2.1.63
image352×176 30.2 KB
--【陆】--:
2.1.59 增加的
--【柒】--:
感谢回复
--【捌】--: phaseddd:
命令名不同: utf8clip 安装后的命令是
utf8clip,而 Claude Code 硬编码调用的是clip。即使装了 utf8clip,Claude Code 依然会调用系统的clip.exe,根本不会走到 utf8clip,如果要替换仍然需要做一个包装器或改名——又回到了 PATH 拦截的套路
.bashrc
alias clip="utf8clip"
需要 .NET Core 3.0+ 运行时
我直接丢到 Claude.ai 上让他给我拉 utf8clip 仓库 转写成 rust
而且正则patch匹配那个容易吃瘪 还是AST解析匹配好些 我群里不是发的有模板来着
--【玖】--:
好吧, 我不用 cli 已经好几个月了
--【拾】--:
image1257×660 68.7 KB
/copy和直接从回复里面手动复制都会
--【拾壹】--:
嗯 ?还有回归问题?
--【拾贰】--:
这两者是完全不同的TUI模式
加这个或者不加的话
操作能力也不一样
我们都是不加的那种旧式的
--【拾叁】--:
感谢佬友补充,已更新主贴
--【拾肆】--:
我也碰到了,而且直接复制内容去粘贴也会乱码,我放假看看
--【拾伍】--:
今天更新2.1.91后,又出现了乱码问题 呜呼
--【拾陆】--: 哈雷彗星:
AST 解析匹配
触及到俺知识盲区了,我晚上再去磨一磨
--【拾柒】--:
CLAUDE_CODE_NO_FLICKER=1
我是加上这个配置后,再复制或者/export都乱码,去掉就不乱码
--【拾捌】--:
当然只有cli有
--【拾玖】--:
我都没理解, 有 /copy 这个命令吗 我的CC 怎么没提示
这是自定义命令吗 还是自身的命令?

