PowerShell UTF-8 BOM CRLF, 파일 쓰는 명령마다 결과가 달랐다

2026.10.10 · 밥

지난 글에서 git 시험을 하던 날, 한글이 든 PowerShell 스크립트를 돌렸더니 문법 오류가 났다. 근데 오류 난 줄엔 아무 문제가 없었다. 알고 보니 인코딩이었다. 내친김에 파일 쓰는 명령마다 결과가 어떻게 다른지 다 재 봤다.

이번 시험에선 LF 를 넣은 문자열을 [IO.File]::WriteAllText 에 UTF8Encoding($false) 와 함께 넘겼더니 BOM 없는 UTF-8 로 써졌다. 끝에 CRLF 도 붙지 않았다. 윈도우 PowerShell 5.1 기본값으로는 Out-File 이랑 > 는 UTF-16, Set-Content 는 시스템 코드페이지, -Encoding UTF8 은 BOM 을 붙였고, 줄 끝도 CRLF 였다.

PowerShell 5.1 명령별로 직접 재 봤다

말로만 들으면 헷갈려서 직접 쟀다. 프로필 영향을 빼려고 powershell.exe -NoProfile 로 새로 띄웠다. "가나", 줄바꿈 LF, "다" 이렇게 같은 문자열을 명령마다 파일로 쓰고, 파일 앞 4바이트랑 CR(0D) 개수를 셌다.

같은 문자열인데 앞 바이트가 명령마다 달랐다
같은 문자열인데 앞 바이트가 명령마다 달랐다
명령앞 바이트뜻CR
Set-ContentB0 A1 B3 AACP949(한국어 코드페이지)1
Set-Content -Encoding UTF8EF BB BF EAUTF-8, BOM 있음1
Out-FileFF FE 00 ACUTF-16LE, BOM 있음1
Out-File -Encoding utf8EF BB BF EAUTF-8, BOM 있음1
> 리다이렉트FF FE 00 ACUTF-16LE, BOM 있음1
[IO.File]::WriteAllTextEA B0 80 EBUTF-8, BOM 없음0

같은 문자열인데 결과가 네 가지. 솔직히 좀 어이없었다.

CR 이 1인 것도 재밌다. 문자열 안의 LF 는 그대로 두고, 명령이 끝에 붙이는 줄바꿈만 CRLF 로 썼다. 그러니까 한 파일 안에 LF 랑 CRLF 가 섞인다. WriteAllText 는 끝에 아무것도 안 붙여서 0 이다.

PowerShell 인코딩 문서를 열어 보니 측정이랑 그대로 맞았다. 5.1 에서 Out-File 이랑 > 는 UTF-16LE, Set-Content 는 시스템 ANSI 코드페이지를 쓰고, UTF8 은 BOM 이 붙는다고 적혀 있다. 문서에도 기본 인코딩이 일관되지 않다고 써 놨다.

프로필에 따라 결과가 또 달랐다

같은 PC 에서 평소 쓰는 셸로도 인코딩을 재 봤다. 이번엔 "가나"만 써서 파일 앞 바이트를 확인했다. > 랑 Out-File 은 UTF-8 BOM 으로 나왔다. 알고 보니 이 셸 프로필에 $PSDefaultParameterValues 로 Out-File 기본 인코딩이 잡혀 있었다.

$PSDefaultParameterValues.Keys
Out-File:Encoding

근데 Set-Content 는 여전히 CP949 였다. Out-File 만 바꿔 놨으니까. 문서에도 > 는 Out-File 을 부르는 거라 이 설정을 따른다고 나와 있다. 이런 기본 인코딩 설정이 있으면 다른 PC 나 -NoProfile 로 돌렸을 때 파일 인코딩이 달라질 수 있다.

한글 든 .ps1 이 깨진 이유

측정 스크립트를 처음엔 BOM 없는 UTF-8 로 저장했다. 한글 문자열이 들어 있었는데 돌리자마자 이랬다.

Unexpected token 'PSVersion' in expression or statement.
The string is missing the terminator: ".

오류 난 줄은 멀쩡했다. 5.1 은 BOM 없는 스크립트를 시스템 ANSI 코드페이지로 읽는다고 문서에 나와 있고, BOM 없는 UTF-8 스크립트에 ASCII 가 아닌 글자가 있으면 깨질 수 있다고도 적혀 있다. 이번 오류도 한글이 든 UTF-8 스크립트를 그렇게 읽으면서 난 걸로 보인다. 한글을 [char]0xAC00 같은 코드로 바꾼 뒤엔 측정이 돌아갔다. 스크립트를 UTF-8 BOM 으로 저장해도 된다고 문서엔 나오는데 그건 안 해 봤다.

BOM 없는 UTF-8 에 LF 로 쓰는 법

결국 내가 쓰는 건 이 한 줄이다.

[IO.File]::WriteAllText($path, $text, (New-Object Text.UTF8Encoding $false))

이 코드는 줄바꿈을 바꾸지 않는다. LF 로 쓰려면 $text 안의 줄바꿈부터 LF 여야 하고, CRLF 가 들어 있으면 그대로 남는다. 나는 $path 를 늘 전체 경로로 준다.

파일이 어떻게 써졌는지 볼 때는 앞 바이트를 찍어 본다.

[IO.File]::ReadAllBytes($path)[0..3] | ForEach-Object { '{0:X2}' -f $_ }

EF BB BF 로 시작하면 BOM, FF FE 면 UTF-16 이다. PowerShell 7 은 기본이 BOM 없는 UTF-8 이라고 문서에 나오는데 나는 5.1 만 써서 확인은 못 했다.

다음엔 이 블로그를 Node 스크립트 하나로 만든 얘기를 하려고 한다.