about_Arrays — PowerShell 배열 다루기
about_Arrays — PowerShell 배열 다루기
여러 값을 한 변수에 묶어 두고 싶을 때, 파워셸에서는 배열(array)을 써요. 배열은 아이템들을 모아 두는 데이터 구조인데, 같은 타입의 값만 담을 수도 있고 서로 다른 타입을 섞을 수도 있어요. Windows PowerShell 3.0부터는 아이템이 0개 또는 1개뿐인 경우에도 배열이 가진 성질을 일부 쓸 수 있게 됐는데, 이 얘기는 뒤에서 자세히 다룰게요.
본문
배열 만들고 초기화하기
배열을 만들고 값을 넣으려면, 변수에 값을 여러 개 지정하면 돼요. 배열에 저장되는 값들은 쉼표(,)로 구분하고, 변수 이름과는 대입 연산자(=)로 나눠요.
예를 들어 22, 5, 10, 8, 12, 9, 80이라는 정수 일곱 개를 담는 $A 배열을 만들고 싶다면 이렇게 입력하면 됩니다.
$A = 22,5,10,8,12,9,80
쉼표를 활용하면 아이템이 하나뿐인 배열도 만들 수 있어요. 쉼표를 그 아이템 앞에 붙이면 됩니다.
예를 들어 7이라는 값 하나만 담는 $B 배열은 이렇게 만들어요.
$B = ,7
범위 연산자(..)로 배열을 만들고 초기화할 수도 있어요. 아래 예시는 5부터 8까지의 값을 담은 배열을 만듭니다.
$C = 5..8
그 결과 $C에는 5, 6, 7, 8 네 개의 값이 들어 있어요.
데이터 타입을 따로 지정하지 않으면, 파워셸은 배열을 객체 배열(System.Object[])로 만들어요. 배열의 데이터 타입이 궁금하면 GetType() 메서드로 확인할 수 있어요.
$A.GetType()
특정 타입의 값만 담을 수 있는 강한 타입의 배열을 만들려면, 변수를 배열 타입으로 캐스트하면 됩니다. 예를 들어 string[], long[], **int32[]**처럼요. 배열로 캐스트하려면 변수 이름 앞에 대괄호로 감싼 배열 타입을 붙여 줘요.
[Int32[]]$ia = 1500, 2230, 3350, 4000
그 결과 $ia 배열에는 정수만 담을 수 있어요.
.NET에서 지원하는 타입이라면 어떤 타입으로든 캐스트해서 배열을 만들 수 있어요. 예를 들어 Get-Process가 가져오는 프로세스 객체들은 System.Diagnostics.Process 타입이죠. 프로세스 객체들의 강한 타입 배열을 만들고 싶다면 다음 명령을 입력합니다.
[Diagnostics.Process[]]$zz = Get-Process
배열 부분식 연산자 (array subexpression operator)
배열 부분식 연산자는 그 안에 적힌 문장들로부터 배열을 만들어 줘요. 문장이 무엇을 만들어 내든, 그 결과를 배열에 담아요. 아이템이 0개든 1개든 상관없이요.
배열 연산자의 문법은 다음과 같아요.
@( ... )
배열 연산자로 0개 또는 1개의 객체로 된 배열을 만들 수 있어요. 예를 들어:
$a = @("Hello World")
$a.Count
1
$b = @()
$b.Count
0
배열 연산자는 스크립트에서 객체를 가져오는데 몇 개가 올지 모를 때 특히 유용해요. 예를 들어:
$p = @(Get-Process Notepad)
배열 부분식 연산자에 대한 더 자세한 내용은 about_Operators에서 다룰게요.
배열 요소 접근하고 사용하기
배열 읽기
배열은 변수 이름으로 참조할 수 있어요. 배열에 들어 있는 모든 요소를 화면에 보여 주고 싶으면 배열 이름을 그대로 호출하면 됩니다. 예를 들어 $a가 0부터 9까지의 숫자로 이루어진 배열이라면:
$a
0
1
2
3
4
5
6
7
8
9
배열의 요소는 인덱스(index)로 참조할 수 있어요. 인덱스 번호를 대괄호 안에 넣으면 되고, 인덱스 값은 0부터 시작합니다. 예를 들어 $a 배열의 첫 번째 요소를 보여 주려면:
$a[0]
0
$a 배열의 세 번째 요소를 보여 주려면 이렇게 입력해요.
$a[2]
2
배열의 일부만 가져올 때는 인덱스에 범위 연산자를 쓰면 돼요. 예를 들어 배열의 두 번째부터 다섯 번째 요소까지 가져오고 싶다면:
$a[1..4]
1
2
3
4
음수는 배열의 끝에서부터 세요. 예를 들어 -1은 배열의 마지막 요소를 가리켜요. 배열의 마지막 세 요소를 인덱스 오름차순으로 보여 주고 싶다면:
$a = 0 .. 9
$a[-3..-1]
7
8
9
음수 인덱스를 내림차순으로 입력하면 출력 결과도 달라져요.
$a = 0 .. 9
$a[-1..-3]
9
8
7
다만 이 표기법을 쓸 때는 조심해야 해요. 이 표기는 배열의 끝 경계에서 시작 경계로 순환해 버리거든요.
$a = 0 .. 9
$a[2..-2]
2
1
0
9
8
또 하나 흔히 하는 실수가 $a[0..-2]가 배열의 마지막 요소만 뺀 모든 요소를 가리킨다고 생각하는 거예요. 실제로는 배열의 첫 번째, 마지막, 그리고 마지막에서 두 번째 요소를 가리킵니다.
더하기 연산자(+)로 범위와 요소 목록을 조합할 수도 있어요. 예를 들어 인덱스 위치 0, 2, 그리고 4부터 6까지의 요소를 보여 주고 싶다면:
$a = 0 .. 9
$a[0,2+4..6]
0
2
4
5
6
여러 범위와 개별 요소를 함께 나열할 때도 더하기 연산자를 쓸 수 있어요. 예를 들어 0부터 2까지, 4부터 6까지, 그리고 8번째 위치의 요소를 나열하려면:
$a = 0..9
$a[+0..2+4..6+8]
0
1
2
4
5
6
8
배열 요소 반복하기
foreach, for, while 같은 반복 구조로도 배열의 요소를 참조할 수 있어요. 예를 들어 foreach 반복문으로 $a 배열의 요소를 보여 주려면:
$a = 0..9
foreach ($element in $a) {
$element
}
0
1
2
3
4
5
6
7
8
9
foreach 반복문은 배열 끝에 도달할 때까지 배열을 순회하면서 각 값을 돌려줘요.
for 반복문은 배열의 요소를 살펴보면서 카운터를 증가시킬 때 유용해요. 예를 들어 배열에서 값을 하나 걸러 하나씩 돌려주고 싶다면:
$a = 0..9
for ($i = 0; $i -le ($a.Length - 1); $i += 2) {
$a[$i]
}
0
2
4
6
8
while 반복문으로는 정의한 조건이 더 이상 참이 아닐 때까지 배열 요소를 보여 줄 수 있어요. 예를 들어 배열 인덱스가 4보다 작은 동안 $a 배열의 요소를 보여 주고 싶다면:
$a = 0..9
$i=0
while($i -lt 4) {
$a[$i]
$i++
}
0
1
2
3
배열의 속성
Count / Length / LongLength
파워셸에서 배열이 담고 있는 아이템 개수를 알려 주는 속성은 세 가지가 있어요.
-
Count — 배열뿐 아니라 어떤 컬렉션이든 아이템 개수를 확인할 때 가장 흔히 쓰는 속성이에요. 값의 타입은
[int32]예요. Windows PowerShell 5.1(그 이하)에서는 Count가 Length의 별칭 속성이었어요. -
Length — 값의 타입은
[int32]이고, Count와 같은 값을 담아요.[!NOTE] 배열에서는 Count와 Length가 동일하지만, 다른 타입에서는 Length가 다른 의미를 가질 수 있어요. 예를 들어 문자열의 Length는 그 문자열의 문자 개수예요. 하지만 Count 속성은 항상
1이죠. -
LongLength — 값의 타입은
[int64]예요. 2,147,483,647개보다 많은 요소를 담는 배열에 이 속성을 써요.
$a = 0..9
$a.Count
$a.Length
10
10
Rank
배열의 차원(dimension) 수를 돌려줘요. 파워셸에서 대부분의 배열은 차원이 하나뿐입니다. 아래 예시처럼 다차원 배열을 만든다고 생각해도요.
$a = @(
@(0,1),
@("b", "c"),
@(Get-Process)
)
"`$a rank: $($a.Rank)"
"`$a length: $($a.Length)"
"`$a[2] length: $($a[2].Length)"
"Process `$a[2][1]: $($a[2][1].ProcessName)"
이 예시는 배열을 담고 있는 1차원 배열을 만드는 거예요. 이런 걸 들쭉날쭉한 배열(jagged array) 이라고 불러요. Rank 속성이 이 배열이 1차원임을 보여 줍니다. 들쭉날쭉한 배열의 항목에 접근할 때는 인덱스를 각각 별도의 대괄호([]) 안에 넣어야 해요.
$a rank: 1
$a length: 3
$a[2] length: 348
Process $a[2][1]: AcroRd32
다차원 배열은 행 우선 순서(row-major order)로 저장됩니다. 아래 예시는 진짜 다차원 배열을 만드는 방법을 보여 줘요.
[string[,]]$rank2 = [string[,]]::new(3,2)
$rank2.Rank
$rank2.Length
$rank2[0,0] = 'a'
$rank2[0,1] = 'b'
$rank2[1,0] = 'c'
$rank2[1,1] = 'd'
$rank2[2,0] = 'e'
$rank2[2,1] = 'f'
$rank2[1,1]
2
6
d
다차원 배열의 항목에 접근할 때는 인덱스를 한 쌍의 대괄호([]) 안에서 쉼표(,)로 구분해 줘요.
복제나 연결 같은 일부 연산은 다차원 배열을 평평하게(flatten) 만들어야 해요. 평탄화는 배열을 타입 제약이 없는 1차원 배열로 바꾸는 작업인데, 결과 배열은 모든 요소를 행 우선 순서로 담게 됩니다. 다음 예시를 볼게요.
$a = "red",$true
$b = (New-Object 'int[,]' 2,2)
$b[0,0] = 10
$b[0,1] = 20
$b[1,0] = 30
$b[1,1] = 40
$c = $a + $b
$a.GetType().Name
$b.GetType().Name
$c.GetType().Name
$c
출력 결과는 $c가 $a와 $b의 항목들을 행 우선 순서로 담은 1차원 배열임을 보여 줘요.
Object[]
Int32[,]
Object[]
red
True
10
20
30
40
배열의 메서드
Clear
배열의 모든 요소 값을 그 요소 타입의 기본값(default value) 으로 설정해요. Clear() 메서드는 배열의 크기를 되돌리지 않아요.
아래 예시에서 $a는 객체들의 배열이에요.
$a = 1, 2, 3
$a.Clear()
$a | % { $null -eq $_ }
True
True
True
이번 예시에서 $intA는 정수를 담도록 명시적으로 타입이 지정된 배열이에요.
[int[]] $intA = 1, 2, 3
$intA.Clear()
$intA
0
0
0
ForEach()
배열의 모든 요소를 반복하면서 각 요소에 대해 지정한 연산을 수행할 수 있게 해 줘요.
ForEach() 메서드는 서로 다른 동작을 하는 여러 오버로드(overload)를 가지고 있어요.
ForEach(scriptblock expression)
ForEach(scriptblock expression, object[] arguments)
ForEach(type convertToType)
ForEach(string propertyName)
ForEach(string propertyName, object[] newValue)
ForEach(string methodName)
ForEach(string methodName, object[] arguments)
ForEach(scriptblock expression)
ForEach(scriptblock expression, object[] arguments)
이 메서드는 PowerShell v4에서 추가됐어요.
[!NOTE] 이 문법은 스크립트블록(scriptblock)을 사용하도록 요구해요. 스크립트블록이 유일한 매개변수라면 괄호는 생략할 수 있어요. 또 메서드와 여는 괄호나 중괄호 사이에 공백이 있어선 안 됩니다.
아래 예시는 ForEach() 메서드를 사용하는 방법을 보여 줘요. 여기서는 배열 요소들의 제곱 값을 만들어 내는 게 목적이에요.
$a = @(0 .. 3)
$a.ForEach({ $_ * $_})
0
1
4
9
ForEach-Object의 ArgumentList 매개변수처럼, arguments 매개변수는 인자를 받도록 구성된 스크립트블록에 인자 배열을 넘겨 줄 수 있게 해 줘요.
ArgumentList의 동작을 더 자세히 알고 싶으면 about_Splatting 문서를 참고하세요.
ForEach(type convertToType)
ForEach() 메서드로 요소들을 다른 타입으로 캐스트할 수 있어요. 다음 예시는 문자열 날짜 목록을 [datetime] 타입으로 변환하는 방법을 보여 줍니다.
("1/1/2017", "2/1/2017", "3/1/2017").ForEach([datetime])
Sunday, January 1, 2017 12:00:00 AM
Wednesday, February 1, 2017 12:00:00 AM
Wednesday, March 1, 2017 12:00:00 AM
ForEach(string propertyName)
ForEach(string propertyName, object[] newValue)
ForEach() 메서드는 컬렉션의 모든 항목에 대해 속성 값을 가져오거나 설정할 때도 쓸 수 있어요.
# Set all LastAccessTime properties of files to the current date.
(dir 'C:\Temp').ForEach('LastAccessTime', (Get-Date))
# View the newly set LastAccessTime of all items, and find Unique entries.
(dir 'C:\Temp').ForEach('LastAccessTime') | Get-Unique
Wednesday, June 20, 2018 9:21:57 AM
[!NOTE]
ForEach()메서드는 열거(enumeration)하기 전에 속성을 컬렉션으로 감싸요(wrap).ForEach()를 쓰면 보통 두 배열의 모든 항목을 돌려주지만, 감싸인 컬렉션의 요소에 접근하려면 인덱스를 두 개 써야 해요.
$myObject 객체가 값 하나짜리 속성과 정수 11개짜리 배열 속성을 가진 다음 예시를 볼게요.
$myObject = [pscustomobject]@{
singleValue = 'Hello'
arrayValue = @(0..10)
}
ForEach() 메서드로 객체의 속성에 접근하면 그 속성이 컬렉션으로 감싸져요.
PS> $myObject.ForEach('singleValue').GetType().Name
Collection`1
PS> $myObject.ForEach('singleValue')[0].GetType().Name
String
PS> $myObject.ForEach('singleValue') # Enumerate the collection object
Hello
배열의 요소에 접근하려면 인덱스를 두 개 사용해야 해요.
PS> $myObject.ForEach('arrayValue').GetType().Name
Collection`1
# A single Collection item
PS> $myObject.ForEach('arrayValue').Count
1
# First item in the collection is an array of 11 items
PS> $myObject.ForEach('Value')[0].Count
11
# Access the first item in the array of 11 items
PS> $myObject.ForEach('Value')[0][0]
0
이건 각 객체의 Value 속성에 접근할 때 ForEach() 메서드를 스크립트블록과 함께 쓰는 방식과는 달라요.
PS> $myObject.ForEach({$_.Value}).Count # An array of 11 items
11
배열이나 중첩 객체처럼 복잡한 속성 타입에 접근할 때 감싸지는 동작을 피하고 싶다면 스크립트블록 문법을 사용하면 돼요.
ForEach(string methodName)
ForEach(string methodName, object[] arguments)
ForEach() 메서드로 컬렉션의 모든 항목에 대해 객체의 메서드를 실행할 수 있어요.
("one", "two", "three").ForEach("ToUpper")
ONE
TWO
THREE
ForEach-Object의 ArgumentList 매개변수처럼, arguments 매개변수는 인자를 받도록 구성된 스크립트블록에 값 배열을 넘겨 줄 수 있게 해 줘요.
[!NOTE] Windows PowerShell 3.0부터는 컬렉션의 각 항목에 대해 속성을 가져오고 메서드를 실행하는 작업을 "스칼라 객체와 컬렉션의 메서드(Methods of scalar objects and collections)"로도 할 수 있어요. 자세한 내용은 about_Methods 문서에서 확인할 수 있어요.
Where()
배열의 요소를 걸러 내거나 선택할 수 있게 해 줘요. 스크립트블록의 평가 결과가 0(영), 빈 문자열, $false, $null과 다른 값이어야 그 요소가 Where() 이후에 남아요. 불리언 평가에 대한 자세한 내용은 about_Booleans 문서를 참고하세요.
Where() 메서드의 정의는 하나뿐이에요.
Where(scriptblock expression[, WhereOperatorSelectionMode mode
[, int numberToReturn]])
[!NOTE] 이 문법은 스크립트블록을 사용하도록 요구해요. 스크립트블록이 유일한 매개변수라면 괄호는 생략할 수 있어요. 또 메서드와 여는 괄호나 중괄호 사이에 공백이 있어선 안 됩니다.
Expression은 필터링에 필요한 스크립트블록이고, 선택 인자 mode는 추가 선택 기능을, 선택 인자 numberToReturn은 필터에서 돌려받을 항목 수를 제한하는 기능을 제공해요.
mode의 값은 WhereOperatorSelectionMode enum 값이어야 해요:
Default(0) - 모든 항목을 돌려줌First(1) - 첫 번째 항목을 돌려줌Last(2) - 마지막 항목을 돌려줌SkipUntil(3) - 조건이 참이 될 때까지 항목을 건너뛰고, 나머지 모든 항목을 돌려줌 (조건이 참인 첫 번째 항목 포함)Until(4) - 조건이 참이 될 때까지 모든 항목을 돌려줌Split(5) - 요소 두 개짜리 배열을 돌려줌- 첫 번째 요소는 조건에 맞는 항목들
- 두 번째 요소는 나머지 항목들
다음 예시는 배열에서 모든 홀수를 선택하는 방법을 보여 줘요.
(0..9).Where{ $_ % 2 }
1
3
5
7
9
다음 예시는 빈 문자열이 아닌 것들을 선택하는 방법이에요.
('hi', '', 'there').Where{ $_ }
hi
there
Default
Default 모드는 Expression 스크립트블록으로 항목을 걸러 줘요.
numberToReturn을 지정하면 돌려줄 최대 항목 수를 정해요.
# Get the zip files in the current users profile, sorted by LastAccessTime
$Zips = dir $Env:USERPROFILE -Recurse '*.zip' | Sort-Object LastAccessTime
# Get the least accessed file over 100MB
$Zips.Where({$_.Length -gt 100MB}, 'Default', 1)
[!NOTE]
Default모드와First모드는 둘 다 처음 (numberToReturn)개 항목을 돌려주기 때문에 서로 바꿔 써도 돼요.
Last
$h = (Get-Date).AddHours(-1)
$logs = dir 'C:\' -Recurse '*.log' | Sort-Object CreationTime
# Find the last 5 log files created in the past hour
$logs.Where({$_.CreationTime -gt $h}, 'Last', 5)
SkipUntil
SkipUntil 모드는 컬렉션에서 객체가 스크립트블록 표현식 필터를 통과할 때까지 모든 객체를 건너뛰어요. 그 다음에는 테스트하지 않고 나머지 모든 컬렉션 항목을 돌려줍니다. 통과하는 항목 하나만 테스트 돼요.
즉 돌려받는 컬렉션에는 테스트되지 않은 통과 항목과 통과하지 못한 항목이 모두 담겨 있을 수 있어요.
돌려받는 항목 수는 numberToReturn 인자에 값을 넘겨 제한할 수 있어요.
$computers = "Server01", "Server02", "Server03", "localhost", "Server04"
# Find the first available online server.
$computers.Where({ Test-Connection $_ }, 'SkipUntil', 1)
localhost
Until
Until 모드는 SkipUntil 모드를 뒤집은 거예요. 항목 하나가 스크립트블록 표현식을 통과할 때까지 컬렉션의 모든 항목을 돌려줍니다. 항목 하나가 표현식을 통과 하면 Where() 메서드는 항목 처리를 멈춰요.
즉 먼저 나오는 통과하지 못한 항목 묶음을 Where() 메서드로 받게 돼요. 항목 하나가 통과한 이후 나머지는 테스트되지도, 돌려지지도 않습니다.
돌려받는 항목 수는 numberToReturn 인자에 값을 넘겨 제한할 수 있어요.
# Retrieve the first set of numbers less than or equal to 10.
(1..50).Where({$_ -gt 10}, 'Until')
# This would perform the same operation.
(1..50).Where({$_ -le 10})
1
2
3
4
5
6
7
8
9
10
[!NOTE]
Until과SkipUntil은 둘 다 항목 묶음을 테스트하지 않는다는 전제로 동작해요.
Until은 첫 번째 PASS 이전의 항목들을 돌려줍니다.SkipUntil은 첫 번째 pass 를 포함해 그 이후의 모든 항목을 돌려줘요.
Split
Split 모드는 컬렉션 항목을 두 개의 별도 컬렉션으로 나누거나 그룹 지어요. 스크립트블록 표현식을 통과한 것들과 통과하지 못한 것들이에요.
numberToReturn을 지정하면 첫 번째 컬렉션에 지정한 값을 넘지 않는 만큼의 통과 항목이 들어와요.
나머지 객체들은 표현식 필터를 통과 하더라도 두 번째 컬렉션에 돌려줍니다.
$running, $stopped = (Get-Service).Where({$_.Status -eq 'Running'}, 'Split')
$running
Status Name DisplayName
------ ---- -----------
Running Appinfo Application Information
Running AudioEndpointBu... Windows Audio Endpoint Builder
Running Audiosrv Windows Audio
...
$stopped
Status Name DisplayName
------ ---- -----------
Stopped AJRouter AllJoyn Router Service
Stopped ALG Application Layer Gateway Service
Stopped AppIDSvc Application Identity
...
[!NOTE]
ForEach()와Where()메서드는 모두 내장 멤버(intrinsic members)예요. 내장 멤버에 대한 자세한 내용은 about_Intrinsic_Members 문서를 참고하세요.
배열의 멤버 가져오기
배열의 속성과 메서드(예: Length 속성, SetValue 메서드)를 얻으려면 Get-Member cmdlet의 InputObject 매개변수를 사용하면 돼요.
배열을 Get-Member로 파이프하면 파워셸은 항목을 하나씩 보내고, Get-Member는 배열에 있는 각 항목의 타입을 돌려줘요 (중복은 무시해요).
InputObject 매개변수를 쓰면 Get-Member가 배열 자체의 멤버를 돌려줍니다.
예를 들어 다음 명령은 $a 배열 변수의 멤버를 가져와요.
Get-Member -InputObject $a
Get-Member로 파이프되는 값 앞에 쉼표(,)를 붙여도 배열의 멤버를 얻을 수 있어요. 쉼표는 그 배열을 배열들의 배열에서 두 번째 항목으로 만들어 줘요. 그러면 파워셸이 배열을 하나씩 파이프하고 Get-Member가 배열의 멤버를 돌려줍니다. 다음 두 예시처럼요.
,$a | Get-Member
,(1,2,3) | Get-Member
배열 조작하기
배열의 요소를 바꾸거나, 요소를 추가하거나, 두 배열의 값을 합쳐 세 번째 배열로 만들 수 있어요.
배열에서 특정 요소의 값을 바꾸려면 배열 이름과 바꾸고 싶은 요소의 인덱스를 지정한 다음 대입 연산자(=)로 새 값을 지정하면 돼요. 예를 들어 $a 배열의 두 번째 항목(인덱스 위치 1)을 10으로 바꾸려면:
$a[1] = 10
배열의 SetValue 메서드로도 값을 바꿀 수 있어요. 다음 예시는 $a 배열의 두 번째 값(인덱스 위치 1)을 500으로 바꿉니다.
$a.SetValue(500,1)
+= 연산자를 사용하면 배열에 요소를 추가할 수 있어요. 다음 예시는 $a 배열에 요소를 추가하는 방법을 보여 줘요.
$a = @(0..4)
$a += 5
[!NOTE]
+=연산자를 쓰면 파워셸은 사실 원래 배열의 값과 추가된 값을 담은 새 배열을 만들어요. 이 연산을 여러 번 반복하거나 배열 크기가 너무 크면 성능 문제가 생길 수 있어요.
배열에서 요소를 삭제하는 건 쉽지 않아요. 다만 기존 배열에서 선택된 요소만 담은 새 배열을 만들 수는 있어요. 예를 들어 $a 배열에서 인덱스 위치 2의 값을 뺀 모든 요소로 $t 배열을 만들려면:
$t = $a[0,1 + 3..($a.Length - 1)]
두 배열을 하나로 합치려면 더하기 연산자(+)를 쓰면 돼요. 다음 예시는 배열 두 개를 만들고, 합치고, 합쳐진 배열을 보여 줍니다.
$x = 1,3
$y = 5,9
$z = $x + $y
그 결과 $z 배열은 1, 3, 5, 9를 담게 돼요.
배열을 삭제하려면 배열에 $null 값을 대입하면 됩니다. 다음 명령은 $a 변수의 배열을 삭제해요.
$a = $null
Remove-Item cmdlet을 쓸 수도 있지만, 특히 배열이 클 때는 $null을 대입하는 편이 더 빨라요.
0개 또는 1개의 배열
Windows PowerShell 3.0부터 스칼라 타입과 0개 또는 1개의 객체로 된 컬렉션은 Count와 Length 속성을 가져요. 또 배열 인덱스 표기법으로 단일(singleton) 스칼라 객체의 값에 접근할 수 있어요. 이 덕분에 컬렉션을 기대하는 명령에 항목이 두 개 미만으로 들어와 생기는 스크립트 오류를 피할 수 있어요.
다음 예시는 객체가 없는 변수의 Count와 Length가 0임을 보여 줘요.
PS> $a = $null
PS> $a.Count
0
PS> $a.Length
0
다음 예시는 객체가 하나 있는 변수의 Count와 Length가 1임을 보여 줍니다. 배열 인덱스로 객체의 값에 접근할 수도 있어요.
PS> $a = 4
PS> $a.Count
1
PS> $a.Length
1
PS> $a[0]
4
PS> $a[-1]
4
컬렉션이나 단일 객체를 돌려줄 수 있는 명령을 실행할 때, Count나 Length 속성을 검사하지 않고 배열 인덱스로 객체의 값에 접근할 수 있어요. 다만 결과가 단일 객체(싱글턴)인데 그 객체가 Count나 Length 속성을 가진다면, 그 속성들의 값은 그 싱글턴 객체에 속한 것이지 컬렉션의 항목 수를 나타내는 게 아니에요.
아래 예시에서 명령은 문자열 객체 하나를 돌려줘요. 그 문자열의 Length는 4예요.
PS> $result = 'one','two','three','four' | Where-Object {$_ -like 'f*'}
PS> $result.GetType().FullName
System.String
PS> $result
four
PS> $result.Count
1
PS❯ $result.Length
4
$result가 문자열 배열이 되게 하려면 변수를 배열로 선언해야 해요.
이 예시에서 $result는 문자열 배열이에요. 배열의 Count와 Length는 1이고, 첫 번째 요소의 Length는 4예요.
PS> [string[]]$result = 'one','two','three','four' |
Where-Object {$_ -like 'f*'}
PS> $result.GetType().FullName
System.String[]
PS> $result
four
PS> $result.Count
1
PS> $result.Length
1
PS> $result[0].Length
4
System.Tuple 객체의 인덱싱 지원
PowerShell 6.1부터는 배열과 비슷하게 Tuple 객체의 인덱스 접근을 지원해요. 예를 들어:
PS> $tuple = [Tuple]::Create(1, 'test')
PS> $tuple[0]
1
PS> $tuple[1]
test
PS> $tuple[0..1]
1
test
PS> $tuple[-1]
test
배열이나 다른 컬렉션 객체와 달리 Tuple 객체는 파이프라인이나 객체 배열을 지원하는 매개변수를 통과할 때 단일 객체로 취급돼요.
자세한 내용은 System.Tuple 문서를 참고하세요.
IDictionary<TKey, TValue>를 구현하는 .NET 타입의 인덱싱
파워셸은 제네릭 IDictionary<TKey, TValue> 인터페이스를 구현하는 타입의 진짜 인덱서를 호출하지 않아요. 대신 키가 주어지면 TryGetValue()로 키의 존재를 검사하고, 키가 없으면 $null을 돌려줍니다.
반면 Item(<key>)로 진짜 인덱서를 호출하면 키가 없을 때 메서드가 예외를 던져요.
다음 예시는 그 차이를 보여 줍니다.
PS> [Collections.Generic.Dictionary[string, int]]::new()['nosuchkey']
# No output ($null)
PS> [Collections.Generic.Dictionary[string, int]]::new().Item('nosuchkey')
GetValueInvocationException: Exception getting "Item": "The given key
'nosuchkey' was not present in the dictionary."
멤버 접근 열거 (Member-access enumeration)
PowerShell 3.0부터 목록 컬렉션에 존재하지 않는 멤버에 멤버 접근 연산자로 접근하면, 파워셸은 자동으로 컬렉션의 항목들을 열거하면서 각 항목에 대해 지정한 멤버에 접근하려고 해요. 자세한 내용은 about_Member-Access_Enumeration 문서를 참고하세요.
예시
다음 예시는 파일 두 개를 만들고 결과 객체를 $files 배열 변수에 저장해요. 배열 객체에는 LastWriteTime 멤버가 없으므로 배열의 각 항목에 대해 LastWriteTime 값이 돌아와요.
$files = (New-Item -Type File -Force '/temp/t1.txt'),
(New-Item -Force -Type File '/temp/t2.txt')
$files.LastWriteTime
Friday, June 25, 2021 1:21:17 PM
Friday, June 25, 2021 1:21:17 PM
멤버 접근 열거는 컬렉션의 항목에서 값을 가져오는(가져오기) 것은 가능하지만, 항목의 값을 설정(set) 하는 것은 불가능해요. 예를 들어:
$files.LastWriteTime = (Get-Date).AddDays(-1)
InvalidOperation: The property 'LastWriteTime' cannot be found on this object.
Verify that the property exists and can be set.
값을 설정하려면 메서드를 사용해야 해요.
$files.set_LastWriteTime((Get-Date).AddDays(-1))
$files.LastWriteTime
Thursday, June 24, 2021 1:23:30 PM
Thursday, June 24, 2021 1:23:30 PM
set_LastWriteTime() 메서드는 FileInfo 객체의 숨겨진(hidden) 멤버예요. 다음 예시는 숨겨진 set 메서드를 찾는 방법을 보여 줍니다.
$files | Get-Member -Force -Name set_*
TypeName: System.IO.FileInfo
Name MemberType Definition
---- ---------- ----------
Attributes Property System.IO.FileAttributes Attributes {get;set;}
CreationTime Property datetime CreationTime {get;set;}
CreationTimeUtc Property datetime CreationTimeUtc {get;set;}
IsReadOnly Property bool IsReadOnly {get;set;}
LastAccessTime Property datetime LastAccessTime {get;set;}
LastAccessTimeUtc Property datetime LastAccessTimeUtc {get;set;}
LastWriteTime Property datetime LastWriteTime {get;set;}
LastWriteTimeUtc Property datetime LastWriteTimeUtc {get;set;}
[!CAUTION] 이 메서드는 컬렉션의 각 항목에 대해 실행되므로, 멤버 열거로 메서드를 호출할 때는 주의해야 해요.