PowerShell 5.1에서 한글이 깨질 때 확인할 두 가지
윈도우 기본 PowerShell 5.1에서 스크립트 속 한글이 깨지거나 변수가 비어 나올 때, 파일 인코딩과 변수 표기 두 가지만 고치면 돼요.
윈도우에 기본으로 들어 있는 PowerShell 5.1로 자동화 스크립트를 만들다 보면 한글 때문에 두 번 막혀요. 스크립트 안의 한글이 깨지거나, 한글 바로 앞의 변수가 텅 비어 나오는 경우예요. 애드온 자동 배포 스크립트를 만들면서 둘 다 겪어서, 원인과 해결법을 적어 둘게요.
스크립트 속 한글이 깨질 때: UTF-8 BOM으로 저장하기
PowerShell 5.1은 BOM(파일 맨 앞의 인코딩 표시)이 없는 .ps1 파일을 UTF-8이 아니라 시스템 기본 인코딩으로 읽어요. 한국어 윈도우에서는 CP949예요. 요즘 편집기는 대부분 BOM 없는 UTF-8로 저장하기 때문에, 파일 안의 한글이 깨진 글자로 읽혀요. 문자열이 깨지는 정도로 끝나지 않고, 한글이 들어간 정규식이 아무것도 못 찾거나 따옴표가 어긋나서 구문 오류가 나기도 해요.
해결은 스크립트를 UTF-8 with BOM으로 저장하는 거예요.
- VS Code: 오른쪽 아래 인코딩 표시(
UTF-8) 클릭, "인코딩하여 저장",UTF-8 with BOM선택 - 스크립트로
.ps1파일을 만든다면 BOM을 붙여서 저장하기
$utf8Bom = New-Object System.Text.UTF8Encoding $true
[System.IO.File]::WriteAllText("C:\scripts\release.ps1", $content, $utf8Bom)
BOM이 붙었는지는 파일의 첫 3바이트로 확인할 수 있어요. EF BB BF가 나오면 BOM이 있는 거예요. 폴더 안의 스크립트를 한 번에 확인하는 스크립트는 글 아래에서 내려받을 수 있어요.
# PowerShell 5.1
Get-Content .\release.ps1 -Encoding Byte -TotalCount 3 | ForEach-Object { '{0:X2}' -f $_ }
# PowerShell 7에서는 -Encoding Byte 대신 -AsByteStream
PowerShell 7 이상은 BOM이 없어도 UTF-8로 읽기 때문에 이 문제가 없어요. 작업 스케줄러처럼 powershell.exe(5.1)로 실행되는 곳에서만 조심하면 돼요.
스크립트가 쓰는 파일은 반대로
BOM이 필요한 건 PowerShell이 읽을 .ps1 파일이에요. 스크립트가 고쳐 쓰는 Markdown, JSON, Lua 같은 파일은 다른 프로그램이 읽으니 BOM 없이 쓰는 게 안전해요. 5.1의 Set-Content -Encoding UTF8이나 Out-File -Encoding utf8은 BOM을 붙여서 저장하니, 인코딩 객체를 직접 넘기는 편이 확실해요. 제 배포 스크립트는 BOM 없는 인코딩 객체($false)를 하나 만들어 두고 모든 읽기와 쓰기에 넘겨요.
# tools/auto_release.ps1
$utf8 = [Text.UTF8Encoding]::new($false)
# ...
function Read-Text([string]$Path) { [IO.File]::ReadAllText($Path, $utf8) }
function Write-Text([string]$Path, [string]$Text) { [IO.File]::WriteAllText($Path, $Text, $utf8) }
변수가 비어 나올 때: ${변수}로 감싸기
아래 코드는 "홍길동님 안녕하세요"를 출력할 것 같지만, 실제로는 " 안녕하세요"만 나와요.
$name = "홍길동"
Write-Output "$name님 안녕하세요"
PowerShell은 변수 이름에 한글도 쓸 수 있어서, $name님 전체를 하나의 변수 이름으로 읽어요. 그런 변수는 없으니 빈 값이 들어가요. 오류도 나지 않아서 결과물을 열어 보기 전까지는 모르고 지나가기 쉬워요. 저는 문서 속 기준값 개수를 새 숫자로 바꾸는 코드에 "$count개"라고 썼다가, 숫자가 통째로 사라진 README를 보고 알았어요.
변수 이름이 어디까지인지 중괄호로 알려 주면 돼요.
Write-Output "${name}님 안녕하세요"
# 또는
Write-Output "$($name)님 안녕하세요"
정규식 치환 문자열에서는 $가 두 종류
-replace나 [regex]::Replace의 바꿀 문자열에서 $1, ${1}은 정규식이 찾은 괄호 자리를 뜻해요. 그런데 큰따옴표 문자열 안에서는 PowerShell이 먼저 $를 변수로 풀어 버려요. 정규식용 $는 백틱으로 막고, PowerShell 변수는 중괄호로 끝을 알려 줘야 해요.
# tools/auto_release.ps1
$countEdits = @(
@{ Path = (Join-Path $addonDir "README.md"); Pattern = '\d{4}-\d{2}-\d{2}( 기준 한밤 Mythic\+ 시즌 \d+의 )[\d,]+개'; Replacement = "$date`${1}${count}개" },
# ...
)
백틱을 붙인 ${1}은 정규식이 채울 첫 번째 괄호 자리로 남고, $date와 ${count}는 PowerShell이 값으로 바꿔요.
한눈에 보기
- 한글이 깨지면: 스크립트를 UTF-8 with BOM으로 저장
- 스크립트가 쓰는 데이터 파일은:
UTF8Encoding($false)로 BOM 없이 저장 - 한글 앞 변수가 비면: 변수를 중괄호로 감싸기, 예를 들어
${count}개 - 정규식 치환 문자열 안의
$1은: 백틱으로 막기
댓글 0
아직 댓글이 없어요. 첫 이야기를 남겨 주세요.