Step 7. 변수와 자료형 — 이름표 붙은 상자에 담기
Level 0 — 컴퓨터 조작과 구조의 이해 | 난이도 ★★☆☆☆ | 예상 소요 시간 2~3시간
전제: Step 6 완료. 윈도우 파워쉘에서 진행합니다. 인터넷 연결은 필요 없습니다.
- 준비물: 윈도우 PC, 파워쉘.
- 안전: 오늘은 메모리 안에서 노는 실험뿐이라 100% 안전합니다.
- 주의: 오늘의 최대 함정을 미리 알려 드립니다. 큰따옴표와 작은따옴표가 파워쉘에서는 다르게 작동합니다. 이 하나 때문에 초보들이 수 시간을 헤맵니다. 여러분은 3-4절에서 정면으로 배우고 넘어갈 겁니다.
오늘부터 "프로그래밍"이 시작됩니다. 하지만 겁먹지 마세요. 오늘 배우는 것은 "값에 이름을 붙여 두고 나중에 다시 꺼내 쓰는" 것 — 일상에서 메모하는 행위와 본질이 같습니다. 오늘의 챕터는 전부 손으로 따라 쳐야 합니다. 코드를 눈으로만 읽으면 절대 몸에 배지 않습니다. 틀려도 됩니다. 오류 메시지도 오늘의 교재입니다.
1. 학습 목표
이 챕터를 끝내면 다음을 할 수 있습니다:
- 변수에 값을 저장하고 꺼내 쓴다
- 숫자·문자열·배열의 차이를 구분하고
GetType()으로 자료형을 확인한다 - 큰따옴표(변수 확장)와 작은따옴표(있는 그대로)의 차이를 설명한다
- 명령의 결과를 통째로 변수에 담아 개수를 세고 항목을 꺼낸다
2. 배경 지식 — 오늘의 도구와 개념
오늘의 도구 한눈에 보기
| 구분 | 내용 |
|---|---|
| 언어·환경 | 파워쉘 5.1 — 오늘부터 본격적인 프로그래밍 개념 |
| 오늘의 문법 | $변수 = 값(저장), $변수(꺼내기), @(...)(배열), $( )(문장 속 끼워 넣기) |
| 오늘의 도구 | GetType()(자료형 확인) |
| 필요한 개념 | 변수와 메모리, 자료형(숫자/문자열/배열), 큰따옴표 vs 작은따옴표 |
지금까지 우리는 명령을 치고 결과를 보고 끝냈습니다. Get-Date를 치면 날짜가 나오지만, 그 결과는 화면을 지나가고 사라집니다. 사람이라면 수첩에 적겠죠 — "와이파이 비밀번호 = blue sky 77"처럼 이름을 붙여 값을 저장합니다. 프로그래밍에서 이 수첩 역할을 하는 것이 변수(variable)이고, 적는 내용이 숫자인지 글자인지 목록인지에 따른 종류가 자료형(data type)입니다. 이 두 개념은 앞으로 나올 모든 스크립트의 알파벳입니다.
2-1. 변수 — 이름표 붙은 상자
변수는 "값을 담는, 이름표가 붙은 상자"입니다.
$name = "Lee"
이 한 줄의 의미: "name이라는 이름표의 상자를 만들고, 그 안에 Lee라는 글자를 넣어라." 나중에 $name이라고 부르면 상자 속 내용이 튀어나옵니다.
파워쉘에서 변수 이름은 항상 $로 시작합니다. 이 달러 표시가 "이건 변수다"라는 신호입니다.
2-2. 컴퓨터 안에서는 — 메모리
상자 비유를 조금만 현실로 옮겨 봅시다. 여러분이 $name = "Lee"를 실행하는 순간, 컴퓨터는 메모리(RAM) 어딘가에 "Lee"를 기록하고, name이라는 이름과 그 위치를 짝지어 기억합니다. 파워쉘 창을 닫으면 메모리의 이 기록도 사라집니다 — 변수는 "창이 열려 있는 동안만 유효한 메모"입니다.
(참고: 이 "메모리"라는 단어는 Level 1에서 아주 깊이 다시 만납니다. C 언어와 버퍼 오버플로 공격이 전부 메모리 이야기거든요. 지금은 "변수는 메모리에 저장된다" 한 줄만 기억해 두세요.)
2-3. 자료형 — 상자 속 물건의 종류
상자 안에 뭐가 들었는지에 따라 할 수 있는 일이 다릅니다.
| 자료형 | 예시 | 할 수 있는 일 |
|---|---|---|
| 숫자 (정수) | 3, 42 |
사칙연산 |
| 글자 (문자열, string) | "Lee", "hello" |
붙이기, 자르기, 검색 |
| 목록 (배열, array) | @("a","b","c") |
순서대로 나열, 하나씩 꺼내기 |
"문자열"은 "문자들이 열(줄)처럼 이어진 것"이라는 뜻의 용어입니다. 글자 데이터라고 생각하시면 됩니다. 따옴표로 감싼 것은 전부 문자열입니다 — "3"도 숫자가 아니라 글자 "3"입니다. 이 차이가 3-3절에서 실제로 문제를 일으킵니다.
3. 따라 하기
3-1. 첫 변수 — 저장하고 꺼내기
$name = "Lee"
아무 일도 안 일어난 것 같죠? 정상입니다. 저장 명령은 조용합니다. 이제 꺼내 봅시다:
$name
Lee
출력 읽는 법: $name이라고만 치면 파워쉘은 "상자 속 내용을 보여 줘"로 알아듣고 내용을 출력합니다.
왜 하는가: 이 "저장 → 꺼내기" 두 동작이 모든 스크립트의 기본 걸음입니다. 변수를 쓰면 같은 값을 백 번 써도 이름표 하나로 관리할 수 있고, 값을 바꿀 때도 한 군데만 고치면 됩니다.
3-2. 숫자 변수 — 계산기 되기
$a = 3
$b = 4
$a + $b
7
출력 읽는 법: 7이 바로 나오면 성공입니다. 상자 두 개 속의 숫자를 꺼내 더한 겁니다.
왜 하는가: 숫자가 변수에 들어가면 계산 결과를 저장했다가 다음 계산에 쓸 수 있습니다. 예를 들어 "전체 로그 줄 수에서 에러 줄 수를 빼면 정상 줄 수" 같은 식의 분석이 가능해집니다.
시험 삼아 $a * $b(곱하기), $a / $b(나누기)도 해 보세요. 파워쉘은 그 자리에서 계산기가 됩니다.
3-3. 숫자와 글자는 다르다 — 자료형의 실체
이번엔 일부러 사고를 쳐 봅시다. 입력:
$x = "3"
$y = "4"
$x + $y
예측해 보기: 결과가 7일까요, 아닐까요?
실제 결과 (실측):
34
7이 아니라 34! 따옴표로 감쌌기 때문에 "3"과 "4"는 숫자가 아니라 글자이고, 글자의 +는 "이어 붙이기"입니다. 이게 자료형이 실제로 결과를 바꾸는 순간입니다.
이 상자들의 정체를 확인해 봅시다:
$x.GetType().Name
String
문자열이라고 컴퓨터가 직접 대답합니다. 아까의 $a로 같은 걸 해 보면 Int32(정수)라고 나옵니다.
왜 하는가: "분명 숫자를 넣었는데 계산이 이상하다"는 초보의 고전적 버그입니다. 원인의 9할이 "숫자인 줄 알았는데 문자열이었다"입니다. GetType()은 의심될 때 정체를 밝히는 신분증 확인기라고 생각하세요.
3-4. 오늘의 최대 함정 — 큰따옴표 vs 작은따옴표
문자열 안에서 변수를 쓰고 싶을 때가 있습니다. 두 가지 방법을 나란히 비교해 봅시다. 입력:
"이름: $name"
'이름: $name'
출력:
이름: Lee
이름: $name
출력 읽는 법: 첫 줄(큰따옴표)은 변수가 풀려서 Lee가 들어갔고, 둘째 줄(작은따옴표)은 $name이 글자 그대로 나왔습니다.
왜 이렇게 다른가: 큰따옴표는 "속을 검사해서 변수가 있으면 값으로 바꿔 치운다"(이걸 변수 확장, 영어로 variable expansion이라 합니다). 작은따옴표는 "속을 있는 그대로 취급한다".
언제 뭘 쓰나: 문장 속에 값을 끼워 넣고 싶으면 큰따옴표. $ 기호 자체를 문자로 쓰고 싶으면 작은따옴표. 기본은 큰따옴표로 시작하고, "어? 변수가 안 풀리네?" 하면 따옴표부터 의심하세요.
예측해 보기:
"내 나이: $a + $b 살"은 어떻게 출력될까요? (정답:내 나이: 3 + 4 살—$a와$b는 각각 풀리지만+는 그냥 글자 취급됩니다. 따옴표 안에서 계산은 일어나지 않습니다. 직접 확인해 보세요.)
3-5. 배열 — 여러 개를 한 상자에
이름 여러 개를 다루고 싶습니다. 상자를 세 개 만들 수도 있지만, 목록 상자 하나가 낫습니다:
$list = @("apple", "banana", "kiwi")
@(...)가 "이건 목록이다"라는 표시입니다. 꺼낼 때는 번호표를 씁니다:
$list[0]
apple
출력 읽는 법: banana가 아니라 apple이 나온 게 포인트입니다. 컴퓨터는 번호를 0부터 셉니다. 0번이 첫 번째, 1번이 두 번째입니다. $list[1], $list[2]도 해 보세요.
왜 하는가: 목록은 실전에서 계속 나옵니다 — 로그 파일 목록, 사용자 목록, 서버 목록. 그리고 다음 챕터의 반복문과 만나면 "목록의 모든 항목에 같은 작업"이라는 강력한 패턴이 됩니다.
목록이 몇 개인지 세는 것도 바로 배워 둡시다:
$list.Count
3
.Count는 "개수 세어 줘"입니다. Step 5에서 본 Measure-Object와 역할이 비슷하죠.
3-6. 종합 — 이름 목록 다루기
오늘 배운 것을 모아 봅시다:
$members = @("Kim", "Lee", "Park")
$members.Count
"첫 번째 멤버: $($members[0])"
3
첫 번째 멤버: Kim
새로운 표기 하나: "$($members[0])" — 큰따옴표 안에서 배열의 한 칸을 넣을 때는 $( )로 한 번 감싸야 합니다. "$members[0]"이라고 그냥 쓰면 실측 결과 이렇게 나옵니다:
Kim Lee Park[0]
배열 전체가 풀린 뒤 [0]이 글자로 붙어 버렸습니다 — 파워쉘이 어디까지가 변수인지 헷갈린 겁니다. "큰따옴표 안에서 복잡한 건 $( )에 담아라" — 이것만 기억하세요.
왜 하는가: "목록 + 개수 + 문장에 끼워 넣기" 조합은 앞으로 보고서 문장을 자동 생성할 때 표준 패턴이 됩니다. 예: "검사한 파일: $($files.Count)개".
3-7. 실전 감각 — 명령 결과를 변수에 담기
지금까지는 값을 직접 적어 넣었습니다($a = 3). 그런데 변수의 진짜 위력은 명령의 결과를 통째로 저장할 때 나옵니다:
$now = Get-Date
$now
2026년 9월 9일 수요일 오전 8:31:07
무슨 일이 일어났나: Get-Date의 결과(현재 시각)가 화면에 출력되는 대신 $now라는 상자에 들어갔습니다. 이제 이 값을 원하는 만큼 재사용할 수 있습니다.
한 걸음 더 — Step 5에서 배운 명령과 합쳐 봅시다:
$services = Get-Service
$services.Count
310
(숫자는 컴퓨터마다 다릅니다. 필자의 PC에서는 310이 나왔습니다.)
출력 읽는 법: 컴퓨터의 전체 서비스 목록이 $services라는 배열에 들어갔고, .Count로 개수를 샀습니다. 명령 결과가 배열이 된 겁니다 — 개별 서비스는 $services[0]처럼 번호로도 꺼낼 수 있습니다.
왜 하는가: 이 패턴 — "결과를 변수에 담고 → 개수를 세고 → 필요한 것을 꺼낸다" — 이 앞으로 모든 분석 스크립트의 뼈대입니다. 로그 파일을 읽어 변수에 담고, 에러만 걸러 다른 변수에 담고, 개수로 판단하는 식입니다. Step 8의 반복문과 만나면 그 모습이 완성됩니다.
예측해 보기:
$services를 실행한 직후와 10분 뒤, 두 번의.Count는 같을까요? (정답: 보통 같지만, 그 사이 서비스가 시작되거나 중지되면 달라질 수 있습니다. 변수는 저장된 순간의 스냅샷이라는 점 — 이 감각이 "기록과 현재를 비교한다"는 보안 사고방식의 출발점입니다.)
4. 미션과 연습문제
미션 — 멤버 소개 스크립트
아래 요구사항을 만족하는 5줄 이내의 코드를 직접 작성해 보세요:
- 이름 세 개가 든 배열
$team을 만든다 (본인 포함 아무 이름이나) $team의 개수를 확인한다- 큰따옴표 문자열로
"우리 팀은 N명입니다"를 출력한다 (N은 변수에서 자동으로) "팀장은 OOO입니다"를 출력한다 (배열의 첫 번째 칸 활용)
연습문제
문제 1. "3" + "4"의 결과와 이유를 설명하세요.
문제 2. "이름: $name"과 '이름: $name'의 출력 차이를 설명하세요.
문제 3. 큰따옴표 안에서 배열의 한 칸을 넣고 싶습니다. "$members[0]"이 아니라 어떻게 써야 하나요?
문제 4. $services = Get-Service를 실행한 뒤 창을 닫고 다시 열었습니다. $services.Count는 어떻게 될까요? 왜 그런가요?
5. 모범 답안과 완료 기준
미션 모범 답안
$team = @("Lee", "Kim", "Park")
$team.Count
"우리 팀은 $($team.Count)명입니다"
"팀장은 $($team[0])입니다"
기대 출력:
3
우리 팀은 3명입니다
팀장은 Lee입니다
검증하는 법: 세 번째 출력에서 N 자리에 실제 숫자가 나오면 성공, $team.Count가 글자로 나오면 따옴표 문제(3-4절 복습), 네 번째에서 이상한 문장이 나오면 $( ) 문제(3-6절 복습)입니다.
심화: $team[3]을 출력하면 어떻게 될까요? (힌트: 번호는 0부터 세고, 목록엔 0·1·2번만 있습니다. 직접 해 보세요 — 실측하면 조용히 아무것도 안 나옵니다. "없는 칸은 오류가 아니라 빈 값"이라는 파워쉘의 성격도 이번에 배워 둡시다.)
연습문제 해답
문제 1 해답. 결과는 34입니다. 따옴표로 감싸면 숫자가 아니라 문자열이 되고, 문자열의 +는 더하기가 아니라 "이어 붙이기"입니다. (숫자로 더하려면 따옴표 없이 3 + 4.)
문제 2 해답. 큰따옴표는 변수 확장 — 속의 $name을 값(예: 이름: Lee)으로 바꿔 치웁니다. 작은따옴표는 있는 그대로 — 이름: $name이라는 글자 그대로 출력합니다.
문제 3 해답. "$($members[0])" — $( )로 감싸야 합니다. 그냥 쓰면 배열 전체가 풀리고 [0]이 글자로 붙는 이상한 출력이 나옵니다 (3-6절 실측 참조).
문제 4 해답. 빈 값이 됩니다(또는 오류). 변수는 메모리에만 저장되고 파워쉘 창을 닫으면 사라집니다. 이것이 Step 9에서 "스크립트 파일로 저장"하는 이유입니다 — 파일은 창이 닫혀도 남습니다.
완료 기준 체크리스트
- [ ] 변수에 값을 저장하고 다시 꺼내 출력할 수 있다
- [ ] 큰따옴표와 작은따옴표의 차이를 설명할 수 있다
- [ ]
"3" + "4"가 왜34인지 설명할 수 있다 - [ ]
GetType()으로 변수의 자료형을 확인할 수 있다 - [ ] 배열을 만들고 번호로 항목을 꺼낼 수 있다 (0부터 센다)
- [ ] 명령 결과를 변수에 담아
.Count로 셀 수 있다 - [ ] 미션: 멤버 소개 스크립트를 완성했다
6. 흔한 실수와 해결
벽 1. 변수를 쳤는데 아무것도 안 나온다
증상: $name = "Lee"를 치고 아무 출력도 없음.
원인: 고장이 아닙니다. 저장 명령은 원래 조용합니다.
해결: $name을 한 번 더 쳐서 내용을 확인하세요. "입력했는데 조용하다 = 저장됐다"로 이해하면 됩니다.
벽 2. 문장 안에서 변수가 그대로 찍힌다
증상: "이름: $name"이 이름: $name으로 출력됨.
원인: 작은따옴표 ' '를 쓰고 있습니다. 작은따옴표는 내용을 있는 그대로 취급합니다.
해결: 큰따옴표 " "로 바꾸세요. 이 함정은 모든 초보가 한 번은 겪는 통과의례입니다.
벽 3. 숫자를 더했는데 이어 붙는다
증상: 3 + 4를 기대했는데 34가 나옴.
원인: 값을 따옴표로 감싸서 문자열이 됐습니다. 문자열의 +는 이어 붙이기입니다.
해결: 따옴표 없이 $a = 3처럼 저장하세요. 의심스러우면 $a.GetType().Name으로 신분 확인 — Int32가 나와야 숫자입니다.
벽 4. 배열에서 엉뚱한 게 나온다
증상: 첫 번째 항목을 원했는데 두 번째가 나오거나, 마지막 다음을 부르면 아무것도 안 나옴.
원인: 번호가 0부터 시작한다는 걸 까먹은 겁니다. 첫 번째는 [0], 세 개짜리 목록의 끝은 [2]입니다.
해결: "번호 = 몇 번째 − 1"로 외우세요. 그리고 $list.Count로 목록 길이를 먼저 확인하는 습관을 들이세요.
벽 5. 변수를 만들었는데 잠시 후 없어졌다
증상: 분명 저장했는데 빈 값이 나옴.
원인: 파워쉘 창을 닫았다 열었거나, 다른 창에서 만들었습니다. 변수는 메모리에만 살고, 창마다 별개입니다.
해결: 같은 창에서 이어서 실습하세요. 창을 닫으면 변수는 전부 사라집니다.
7. 정리
오늘의 핵심 표
| 개념 | 비유 | 파워쉘 표기 |
|---|---|---|
| 변수 | 이름표 붙은 상자 (메모리에 저장) | $name = "Lee" |
| 문자열 | 글자 데이터 | "hello" (따옴표 필수) |
| 정수 | 숫자 데이터 | 3 (따옴표 없이) |
| 배열 | 번호표 달린 목록 상자 | @("a","b","c"), [0]부터 |
오늘의 함정 카드
| 상황 | 결과 | 교훈 |
|---|---|---|
"$name" (큰따옴표) |
변수가 풀림 | 값을 끼워 넣을 때 |
'$name' (작은따옴표) |
글자 그대로 | $ 기호 자체를 쓸 때 |
"3" + "4" |
34 |
따옴표 = 문자열 |
3 + 4 |
7 |
따옴표 없음 = 숫자 |
"$list[0]" |
이상한 출력 | 배열 칸은 $($list[0]) |
명령어보다 중요한 감각
"상자 속 물건의 종류를 항상 의식하라." "문자열인 줄 알았는데 숫자였다(혹은 반대)"는 버그는 실제 보안 취약점의 씨앗이 되기도 합니다. 의심스러우면 GetType()으로 신분을 확인하는 습관 — 그게 오늘의 진짜 소득입니다.
알아두면 좋은 것 두 가지: "사용자가 입력한 값을 변수에 담아 명령에 그대로 끼워 넣는" 코드는 인젝션(injection) 공격의 단골 소재입니다 — "외부에서 온 값은 함부로 신뢰하지 않는다"는 철칙의 이유를 Level 2에서 직접 공격해 보며 체감하게 됩니다. 그리고 실전에서는 $a 대신 $loginFailCount처럼 "읽으면 뭔지 아는 이름"을 씁니다. 이름만 봐도 용도가 보이는 코드는 설명서 없이도 읽힙니다.
전부 체크되면 Step 7 완료입니다. 사이드바의 체크박스를 눌러 진도를 저장하세요.