PowerShell에서 "$개수개"라고 썼더니 숫자가 사라졌다
큰따옴표 문자열에서 변수 바로 뒤에 한글을 붙이면 변수가 통째로 빈 값이 된다. 오류도 없다. $()나 ${}로 감싸면 된다.
도구PowerShell 7
증상
파일을 몇 개 옮겼는지 찍으려고 이렇게 썼다.
$made = 3
"링크 $made개"
기대한 건 「링크 3개」인데 「링크 」가 나왔다. 숫자가 사라졌고 오류 한 줄 없다. 노트북을 옮기는 스크립트 두 군데에서 똑같이 당했다. 결과 줄만 보고 「아무것도 안 옮겨졌나?」 하고 한참 헤맸다.
원인·원리
PowerShell은 큰따옴표 문자열 안의 $이름을 변수 값으로 바꿔 넣는다. 이때 변수 이름이 어디까지인지는 「이름에 쓸 수 있는 글자가 이어지는 데까지」로 정한다. 영어·숫자·밑줄만이 아니라 한글 같은 유니코드 글자도 변수 이름에 쓸 수 있다. 그래서 $made개는 「$made 뒤에 개」가 아니라 made개라는 이름의 변수 하나로 읽힌다. 그런 변수는 없으니 빈 문자열이 들어가고, 없는 변수를 읽는 건 기본 설정에서 오류가 아니다.
영어에서는 "$count items"처럼 변수 뒤에 빈칸이 오니까 이 일을 겪을 일이 없다. 한국어는 「3개·3명·3번·3원」처럼 단위가 숫자에 바로 붙어서 걸린다.
고침
변수 이름의 끝을 분명하게 표시한다. 두 방법 다 된다.
$made = 3
"링크 $($made)개" # 부분식 — 괄호 안을 계산한 값을 넣는다
"링크 ${made}개" # 중괄호 — 이름의 범위를 못 박는다
이미 써 둔 스크립트는 한 번 훑는다. 「변수 이름 바로 뒤에 한글」 자리를 찾는 정규식이다.
Select-String -Path .\*.ps1 -Pattern '\$[A-Za-z_][A-Za-z0-9_]*[가-힣]'
다시 확인
$made = 3
"링크 $made개" # 링크 ← 그대로 재현된다
"링크 $($made)개" # 링크 3개
없는 변수를 읽는 순간 바로 오류가 나게 하고 싶으면 스크립트 파일 머리에 엄격 모드를 켠다. 그러면 「'$made개' 변수는 설정되지 않았으므로 가져올 수 없습니다」로 그 자리에서 멈춘다.
Set-StrictMode -Version Latest
함정
- 변수 이름은 대소문자를 가리지 않는다.
$h와$H는 같은 변수라 뒤에 쓴 쪽이 앞 값을 덮는다. 사용자 폴더를$H에 담아 두고 뒤에서$h를 쓰면 엉뚱한 값이 된다. Set-StrictMode는 대화형 터미널에서 켜 두면 그 뒤에 치는 다른 명령·도구가 「변수는 설정되지 않았으므로」로 멈추기도 한다. 스크립트 파일 머리에만 둔다.