Claude Code·Codex 한글 깨짐: Windows에서 원인과 해결

게시 읽는 시간 약 9분 문제 해결

Windows PowerShell 5.1에서 Claude Code에 한글 문장을 그대로 출력하게 하고 결과를 변수에 받았더니 ?덈뀞?섏꽭???쒓? ?뚯뒪??가 나왔습니다. Codex CLI와 Antigravity CLI도 한 글자도 다르지 않게 똑같이 깨졌고요.

가장 흔히 권하는 chcp 65001을 치고 Claude Code로 다시 해 봐도 그대로였습니다.

고칠 곳은 에이전트가 아니라 PowerShell이었습니다. 5.1의 기본 인코딩 때문이거든요. 아래 네 줄을 PowerShell 프로필에 넣으면 출력을 변수로 받을 때와 한글을 파이프로 넘길 때가 모두 고쳐지고, 에이전트가 만든 .ps1은 UTF-8 BOM을 붙여 저장하면 5.1에서 돕니다.

$utf8 = New-Object System.Text.UTF8Encoding $false
[Console]::InputEncoding = $utf8
[Console]::OutputEncoding = $utf8
$OutputEncoding = $utf8

2026년 9월 29일 Windows 11 · Windows PowerShell 5.1 테스트 환경에서 Claude Code 2.1.283, Codex CLI 0.158.0, Antigravity CLI 1.2.12를 직접 실행해 확인했고, PowerShell의 인코딩 규칙은 같은 날 Microsoft Learn 문서로 다시 확인했습니다.

결과를 받아 다시 쓰거나, 한글을 넘겨주거나, 만든 스크립트를 실행하는 경우만 다룹니다. 설치가 아직이라면 Claude Code Windows 설치 글이나 Codex CLI 설치 글부터 보세요.

확인한 버전·환경

  • Claude Code 2.1.296 · Windows 11 · Windows PowerShell 5.1 · 확인일 2026-10-13
  • Codex CLI 0.158.0 · Windows 11 · Windows PowerShell 5.1 · 확인일 2026-09-29
  • Antigravity CLI 1.2.12 · Windows 11 · Windows PowerShell 5.1 · 확인일 2026-09-29

증상으로 고칠 곳 고르기

깨진 모양을 보면 어디를 고칠지 바로 알 수 있습니다.

증상 언제 고칠 곳
?덈뀞?섏꽭??처럼 엉뚱한 글자 결과를 변수·파일로 받을 때 [Console]::OutputEncoding
에이전트가 ?????를 받음 한글을 파이프로 넘길 때 $OutputEncoding
문자열에 " 종결자가 없습니다. 에이전트가 만든 .ps1 실행 파일을 BOM과 함께 저장

출력과 파이프가 깨지는 이유

세 도구에 한글 문장을 그대로 출력하게 하고 결과를 변수에 받은 명령과 결과입니다.

$r = claude -p "Output exactly this Korean text and nothing else: 안녕하세요 한글 테스트"
$r
?덈뀞?섏꽭???쒓? ?뚯뒪??

10월 13일 Claude Code 2.1.296으로 다시 해 봤습니다. 이번에는 프롬프트를 한국어로 바꾸고 --model haiku를 붙였는데, 프로필 없이 띄운 Windows PowerShell 5.1에서 똑같이 깨졌고, 아래 절의 네 줄을 넣자 바로 고쳐졌어요.

Windows PowerShell 5.1 창. 첫 명령은 claude -p로 한글 문장을 그대로 출력하게 해 변수 $r에 받은 것으로, 결과가 물음표가 섞인 깨진 글자로 나옵니다. 이어서 UTF8Encoding을 Console의 InputEncoding·OutputEncoding과 $OutputEncoding에 넣는 명령을 실행한 뒤 같은 명령을 다시 실행하니 안녕하세요 한글 테스트가 정상으로 나옵니다.
같은 창에서 인코딩 네 줄을 넣기 전과 후. 에이전트는 그대로이고 PowerShell 설정만 바꿨습니다.

codex exec와 agy -p도 똑같이 깨졌습니다. 반대 방향도 막혀요. 한글을 파이프로 넘기고 받은 그대로 돌려 달라고 하면 에이전트는 물음표만 받습니다.

"가나다라마 한글" | claude -p "Repeat back exactly the text you received on standard input between [[ and ]], nothing else."
[[????? ??]]

이유는 간단합니다. 한국어 Windows에서 PowerShell 5.1 창을 새로 열면(프로필 없이) 두 값이 이렇거든요.

값 기본값 하는 일
[Console]::OutputEncoding 949(CP949) 외부 프로그램 출력을 읽을 때
$OutputEncoding us-ascii 외부 프로그램에 문자열을 넘길 때

세 도구는 UTF-8로 내보내는데 PowerShell이 CP949로 읽으니 깨진 모양까지 같고, 넘길 때는 ASCII라 한글이 PowerShell 안에서 이미 물음표로 바뀝니다. 받는 순간 잘못 읽혔으므로 | Out-File이나 > 결과.txt로 저장해도 깨진 글자가 그대로 남아요. $OutputEncoding은 파일 저장에는 영향이 없습니다.

Antigravity CLI(agy -p)는 사정이 달랐습니다. 인코딩과 상관없이 파이프 입력을 아예 읽지 않더라고요.

받은 게 없으면 [[EMPTY]]라고 답하게 했더니 설정 전후 모두 [[EMPTY]]였고, agy --help에서 표준 입력을 읽는다고 적힌 것은 --input-format stream-json뿐이었습니다. 긴 한글 문서는 파일로 저장한 뒤 그 파일을 읽으라고 지시하세요.

프로필에 네 줄 넣기

맨 위의 네 줄을 실행한 창에서 같은 명령을 다시 돌렸습니다.

경우 설정 전 설정 후
출력을 변수로 받기 ?덈뀞?섏꽭???쒓? ?뚯뒪?? 안녕하세요 한글 테스트
파이프로 넘기기 [[????? ??]] [[가나다라마 한글]]

세 도구 모두 출력이 제대로 나왔고, Claude Code와 Codex CLI는 파이프로 넘긴 한글을 제대로 받았습니다. $false는 BOM 없는 UTF-8이라는 뜻이고, $OutputEncoding은 대개 [Console]::InputEncoding과 맞춰 두는 게 좋아 네 값을 같게 했습니다.

창을 열 때마다 입력하지 않으려면 프로필(PowerShell이 시작할 때 실행하는 스크립트)에 넣습니다. 메모장이 열리면 네 줄을 붙여 넣고 저장한 뒤 새 창을 여세요.

if (-not (Test-Path $PROFILE)) { New-Item -ItemType File -Path $PROFILE -Force }
notepad $PROFILE

실행 정책이 기본값 Restricted이면 프로필도 실행되지 않습니다. 새 창에서 스크립트 실행이 막혔다고 나오면 Claude Code Windows 설치 글의 실행 정책 오류 부분을 보세요. 이 설정은 PowerShell 창 안에서만 바뀌고, 시스템 로캘은 건드리지 않아 다른 프로그램에는 영향이 없습니다.

chcp 65001로는 안 고쳐진다

가장 흔한 조언은 chcp 65001인데, 직접 해 보니 안 됐습니다. chcp 65001 직후에도 변수로 받은 결과는 ?덈뀞?섏꽭??, 파이프로 넘긴 한글은 ?????였어요(Claude Code 2.1.283). PowerShell이 쓰는 두 값을 찍어 보니 그대로였습니다.

Console.OutputEncoding=949 OutputEncoding=us-ascii

chcp는 콘솔의 코드 페이지를 바꿀 뿐, 이미 실행 중인 PowerShell이 결과를 읽고 넘길 때 쓰는 값은 바꾸지 않습니다. Windows Terminal은 창을 그리는 프로그램이고 인코딩은 그 안의 PowerShell이 정하므로, 프로필의 네 줄이 먼저예요.

이미 ?????로 저장된 파일은 원래 바이트가 사라져 되살릴 수 없으니, 설정을 고친 뒤 다시 실행하세요.

에이전트가 만든 .ps1은 BOM이 필요하다

Claude Code와 Codex CLI에 “한글 안녕하세요를 출력하는 hello.ps1을 만들어 달라”고 하자, 둘 다 Write-Output "안녕하세요" 한 줄을 BOM 없는 UTF-8로 저장했습니다. 이걸 Windows PowerShell 5.1로 실행하면 멈춥니다.

powershell -NoProfile -ExecutionPolicy Bypass -File .\hello.ps1
위치 <프로젝트 경로>\hello.ps1:1 문자:14
+ Write-Output "…
+              ~~~~~~~~~
문자열에 " 종결자가 없습니다.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : TerminatorExpectedAtEndOfString

둘째 줄 따옴표 뒤에는 깨진 글자가 찍힙니다(…로 줄였습니다). 영어 메시지로는 The string is missing the terminator: ".입니다. 5.1은 BOM이 없는 스크립트를 기존 ANSI 코드 페이지(CP949)로 읽기 때문에, UTF-8 한글 바이트가 잘못 읽혀 닫는 따옴표까지 글자 속에 먹힌 거예요.

재미있는 건 두 도구의 반응이었습니다. Claude Code는 파일을 만든 뒤 “5.1에서는 한글이 깨질 수 있으니 UTF-8 with BOM으로 다시 저장하라”고 스스로 알려 줬고, Codex CLI는 done만 답했거든요.

고치는 방법은 이렇습니다.

  1. 이미 만든 파일에 BOM 붙이기. 아래 한 줄은 내용은 두고 BOM만 붙입니다. Resolve-Path를 쓰는 이유는 .NET 파일 함수가 상대 경로를 PowerShell의 현재 폴더가 아니라 프로세스 폴더 기준으로 풀기 때문입니다. 실행 뒤 첫 세 바이트가 EF BB BF가 됐고 안녕하세요가 출력됐습니다.

    $p = (Resolve-Path .\hello.ps1).Path; $t = [IO.File]::ReadAllText($p, (New-Object Text.UTF8Encoding $false)); [IO.File]::WriteAllText($p, $t, (New-Object Text.UTF8Encoding $true))
  2. 처음부터 BOM을 붙이라고 지시하기. Codex CLI에 같은 요청 끝에 Save it as UTF-8 with BOM so Windows PowerShell 5.1 can run it.을 덧붙이자 첫 바이트가 EF BB BF인 파일을 만들었고 바로 실행됐습니다. CLAUDE.md나 AGENTS.md에 “PowerShell 스크립트는 UTF-8 with BOM으로 저장”을 한 줄 적어 두면 매번 말하지 않아도 돼요. 저라면 이쪽을 먼저 해 두겠습니다.

PowerShell 7(v6 이상)을 쓴다면 이 문제는 없습니다. 기본값이 BOM 없는 UTF-8이고 그런 스크립트도 문제없이 읽습니다.

CP949 파일을 맡길 때

오래된 메모·CSV·배치 파일은 CP949로 저장된 경우가 많고, 5.1의 Set-Content도 새 파일을 이 인코딩으로 만듭니다. 그렇게 만든 memo.txt(회의 메모: 다음 주 화요일 3시)를 세 도구에 읽히고 한 줄을 덧붙이게 했더니 반응이 셋 다 달랐습니다.

  • Codex CLI 0.158.0은 셸의 Get-Content로 정확히 읽었습니다(5.1의 Get-Content는 BOM이 없으면 ANSI로 읽습니다). 덧붙일 때도 CP949인 것을 먼저 확인하고 CP949로 써서 기존 줄을 지켰어요.
  • Claude Code 2.1.283(셸 명령 없이 파일 읽기·편집 도구만 허용)은 대체 문자(�)로 읽힌다며 추측하지 않고 멈췄고, 편집 도구가 인코딩을 바꿔 기존 줄이 깨질 수 있다며 고치지 않았습니다. 필요한 셸 명령을 제시하며 허락을 구했고요.
  • Antigravity CLI 1.2.12(-p)는 셸 명령 권한이 자동 거부돼 빈 응답이었습니다. 이 권한 거부는 Antigravity CLI 이전 글에서 다뤘습니다.

맡기기 전에 UTF-8로 바꿔 두면 도구와 상관없이 해결됩니다. 변환한 파일은 BOM이 붙은 UTF-8이었고, Claude Code가 같은 조건에서 정확히 읽었습니다. 원본을 다른 프로그램이 CP949로 계속 써야 한다면 변환하지 말고 지시에 “이 파일은 CP949다”라고 적어 주세요.

Get-Content .\memo.txt | Set-Content -Encoding UTF8 .\memo-utf8.txt

폴더 이름은 문제가 아니었습니다. 한글과 공백이 든 한글 폴더에서 세 도구 모두 폴더 이름을 정확히 답했고, 결과.txt 같은 한글 이름 파일도 이름과 내용이 깨지지 않았습니다. 다만 Claude Code가 세션 기록을 저장하는 폴더 이름에서는 한글이 -로 바뀌어 겹칠 수 있는데, 그 이야기는 Claude Code Windows 경로 문제 글에 있습니다.

스크립트 안의 codex exec가 끝나지 않을 때

다른 프로그램이 띄운 PowerShell 스크립트 안에서 codex exec를 부르자 10분이 지나도 끝나지 않았습니다. 표준 오류에는 Reading additional input from stdin...이 찍혀 있었어요.

codex exec --help대로, 표준 입력이 파이프로 연결돼 있으면 그 내용을 지시에 덧붙이려고 입력이 닫히길 기다린 겁니다. 터미널에서 직접 칠 때는 생기지 않습니다.

cmd에서 < NUL로 표준 입력을 닫자 같은 문구를 찍고 곧바로 끝났습니다. 예약 작업이나 다른 프로그램에서 부를 때는 입력을 명시적으로 닫아 두세요.

참고로 한글 문서라도 .hwp·.hwpx는 인코딩이 아니라 파일 형식이 문제라서 여기서 다룬 설정으로는 풀리지 않아요. 그쪽은 Claude Code로 HWP 파일을 읽고 고쳐 본 결과를 보세요.

codex exec --skip-git-repo-check "Read memo.txt and output its first line." < NUL

마치며

세 도구가 한 글자도 다르지 않게 똑같이 깨졌다는 것 자체가 단서였습니다. 고칠 곳은 에이전트가 아니라 PowerShell이었어요.

출력·파이프 깨짐은 두 기본값(CP949, us-ascii) 때문이라 chcp가 아니라 프로필의 네 줄로 고쳐지고, 에이전트가 만든 .ps1은 BOM을 붙여야 5.1에서 돕니다. CP949로 된 옛 파일은 UTF-8로 바꿔 맡기면 도구에 상관없이 안전하고요.

notepad $PROFILE을 열어 네 줄을 붙여 넣는 것부터 해 보세요. 에이전트 결과를 스크립트에서 다룰 계획이라면 종료 코드와 JSON 출력을 읽는 법을 Claude Code 헤드리스 모드 글에서 이어서 보면 됩니다.

참고한 공식 자료

모두 2026년 9월 29일에 확인했습니다.

변경 이력

  • 2026-10-14 — 근거 없이 Windows Terminal에서도 같다고 적었던 문장을 빼고, 10월 13일 캡처가 한국어 프롬프트와 --model haiku로 찍은 것임을 밝혔습니다.
  • 2026-10-13 — Claude Code 2.1.296에서 같은 실험을 다시 해, 프로필 없는 Windows PowerShell 5.1에서 똑같이 깨지고 인코딩 네 줄을 넣자 바로 고쳐지는 화면을 더했습니다.