PowerShell에서 "$개수개"라고 썼더니 숫자가 사라졌다

큰따옴표 문자열에서 변수 바로 뒤에 한글을 붙이면 변수가 통째로 빈 값이 된다. 오류도 없다. $()나 ${}로 감싸면 된다.

도구PowerShell 7

증상

파일을 몇 개 옮겼는지 찍으려고 이렇게 썼다.

powershell
$made = 3
"링크 $made개"

기대한 건 「링크 3개」인데 「링크 」가 나왔다. 숫자가 사라졌고 오류 한 줄 없다. 노트북을 옮기는 스크립트 두 군데에서 똑같이 당했다. 결과 줄만 보고 「아무것도 안 옮겨졌나?」 하고 한참 헤맸다.

원인·원리

PowerShell은 큰따옴표 문자열 안의 $이름을 변수 값으로 바꿔 넣는다. 이때 변수 이름이 어디까지인지는 「이름에 쓸 수 있는 글자가 이어지는 데까지」로 정한다. 영어·숫자·밑줄만이 아니라 한글 같은 유니코드 글자도 변수 이름에 쓸 수 있다. 그래서 $made개는 「$made 뒤에 개」가 아니라 made개라는 이름의 변수 하나로 읽힌다. 그런 변수는 없으니 빈 문자열이 들어가고, 없는 변수를 읽는 건 기본 설정에서 오류가 아니다.

영어에서는 "$count items"처럼 변수 뒤에 빈칸이 오니까 이 일을 겪을 일이 없다. 한국어는 「3개·3명·3번·3원」처럼 단위가 숫자에 바로 붙어서 걸린다.

고침

변수 이름의 끝을 분명하게 표시한다. 두 방법 다 된다.

powershell
$made = 3
"링크 $($made)개"   # 부분식 — 괄호 안을 계산한 값을 넣는다
"링크 ${made}개"    # 중괄호 — 이름의 범위를 못 박는다

이미 써 둔 스크립트는 한 번 훑는다. 「변수 이름 바로 뒤에 한글」 자리를 찾는 정규식이다.

powershell
Select-String -Path .\*.ps1 -Pattern '\$[A-Za-z_][A-Za-z0-9_]*[가-힣]'

다시 확인

powershell
$made = 3
"링크 $made개"      # 링크        ← 그대로 재현된다
"링크 $($made)개"   # 링크 3개

없는 변수를 읽는 순간 바로 오류가 나게 하고 싶으면 스크립트 파일 머리에 엄격 모드를 켠다. 그러면 「'$made개' 변수는 설정되지 않았으므로 가져올 수 없습니다」로 그 자리에서 멈춘다.

powershell
Set-StrictMode -Version Latest

함정

  • 변수 이름은 대소문자를 가리지 않는다. $h와 $H는 같은 변수라 뒤에 쓴 쪽이 앞 값을 덮는다. 사용자 폴더를 $H에 담아 두고 뒤에서 $h를 쓰면 엉뚱한 값이 된다.
  • Set-StrictMode는 대화형 터미널에서 켜 두면 그 뒤에 치는 다른 명령·도구가 「변수는 설정되지 않았으므로」로 멈추기도 한다. 스크립트 파일 머리에만 둔다.