전문가칼럼

DBMS, DB 구축 절차, 빅데이터 기술 칼럼, 사례연구 및 세미나 자료를 소개합니다.

관리 효율성 증대를 위한 핵심 엔진 : 개체를 내 맘대로 다루기(2)

전문가칼럼
DBMS별 분류
Etc
작성자
dataonair
작성일
2015-05-18 00:00
조회
5108




◎ 연재기사 ◎


관리 효율성 증대를 위한 핵심 엔진 : 개체를 내 맘대로 다루기(1)


관리 효율성 증대를 위한 핵심 엔진 : 개체를 내 맘대로 다루기(2)


관리 효율성 증대를 위한 핵심 엔진 : 파워셸 스크립팅 준비


관리 효율성 증대를 위한 핵심 엔진 : 명령에서 스크립트로



관리 효율성 증대를 위한 핵심 엔진

개체를 내 맘대로 다루기②



지난 달 5번째 파워셸 연재에서는 앞으로 파워셸에서 개체를 다루는 데 필요한 기본 기술을 익혔다. 이번 연재는 파워셸에서 출력 개체의 변환, 내보내기 및 가져오기, 출력이 개체의 컬렉션으로 넘어올 때 각 개체를 처리하는 방법을 살펴본다. 그리고 앞서 4회에서 설명한 파워셸 개체의 멤버인 속성과 메서드를 활용하는 방법을 설명한다. 여기서 설명하는 여러 가지 커맨드렛은 다양한 매개변수 옵션이 있으므로 필히 Get-Help를 통해 사용방법을 자세히 확인해보기 바란다.



출력 개체의 형식 변환

파워셸은 파이프라인 개체를 다른 형식의 데이터로 나타내는 기능을 제공한다. 예를 들어 개체의 형식을 HTML, CSV, 또는 XML 형식으로 변환할 수 있다. 이와 관련해 파워셸에서는 두 가지 다른 동사인 ConvertTo와 Export가 준비돼 있다. 이를 테면ConvertTo-HTML과 같은 커맨드렛을 사용하면 파이프라인에서 개체를 입력으로 받아 파이프라인의 출력으로 변환된 HTML 데이터를 내보낸다. 이때 변환된 데이터는 파워셸 세션의 메모리에 유지되고 이를 파이프라인을 통해 또 다른 명령으로 보내 데이터를 화면이나 파일에 출력한다. 현재 시스템에서 동작 중인 프로세스 정보를 읽어와 csv 형식의 파일로 저장하고 싶다면 다음과 같이 할 수 있다. 실행 결과는 <그림 1>에서 나타냈다. Out-File에 관해서는 다음 절에서 자세히 설명한다.

Get-Process | ConvertTo-CSV | Out-File Process.csv

column_img_1896.jpg

ConvertTo 동사와 관련된 파워셸 커맨드렛은 대표적으로 다음 세 가지다. 이들 커맨드렛은 이름만으로도 어떤 동작을 할지 짐작된다.

- ConvertTo-CSV
- ConvertTo-HTML
- ConvertTo-XML

Export 동사를 사용하는 명령으로 Export-CSV와 Export-CliXML이 대표적이다. 이 두 가지 커맨드렛은 내부적으로 동시에 두 가지 작업을 수행한다. 첫 번째 작업은 데이터를 변환하는 작업이고, 두 번째 작업은 파일과 같은 외부 저장소에 데이터를 쓰는 작업이다. 예를 들어, 프로세스 정보를 csv 형식의 파일로 저장할 경우 다음과 같이 할 수도 있다.

Get-Process | Export-CSV Process.csv

즉 Export 명령은 ConvertTo와 Out-File 두 가지 명령의 기능이 결합되었다고 보면 된다. 따라서 Export 명령의 결과를 다시 파이프라인으로 보내지 못한다. 이러한 변환 작업에서 알아야 할 중요한 사실은 변환 전에는 개체였지만, 변환 후에는 더 이상 개체로서의 구조를 포함하지 않으면 완전히 다른 형식이 된다는 것이다. 이렇게 변환된 데이터를 가지고 정렬이나 선택, 계산과 같은 조작을 하는 것은 쉽지 않다. 따라서 커맨드렛을 사용할 때는 해당 개체의 조작이 모두 끝난 뒤에 하는 것이 좋다.



출력을 파일로 보내기

파워셸에서 커맨드렛의 처리 결과를 파일로 저장할 때 사용하는 명령이 Out-File이다. 이 커맨드렛은 개체를 텍스트로 렌더링하며 셸에서 개체를 화면에 텍스트로 렌더링 하는 데 사용하는 동일한 기술을 사용한다. 이 동작은 개체의 형식을 변경하지 않기 때문에 개체를 변환하거나 내보내기 하는 것과는 다르다. 즉, 셸에서 화면에 나타난 것을 단순히 캡처하는 동작일 뿐이다.

Out-File에는 다양한 매개변수가 있어, 파일의 이름을 지정하고, 기존 파일의 내용에 붙이거나 문자 인코딩 등을 지정할 수 있다. Out-File의 결과는 보통 사람이 읽기 위한 용도이므로 이를 다시 읽어 들여 데이터를 정렬하거나 선택, 계산하는 조작하면 어렵거나 불가능할 수 있다. 파워셸에서 커맨드렛을 결합하여 사용할 때는, 각 파이프라인의 내용을 잘 추적해야 한다. 파이프라인에서 각 명령이 실행될 때, 해당 명령이 입력됐던 것과는 다른 형식을 출력할 수도 있다. 예를 들어 다음과 같은 명령 구문이 실행되었을 때 각 커맨드렛의 실행 결과로 출력이 어떻게 바뀌는지 살펴보자.

Get-Service |
Sort-Object Property Status |
Select-Object Property Name,Status |
ConvertTo-CSV |
Out-File FilePath ServiceList.csv

Get-Service를 실행한 후 파이프라인에는 System.Service Process.ServiceController 형식의 개체를 포함한다. 그 다음 Sort-Object로 넘어간 후 파이프라인에는 여전히 Service Controller 개체가 있다. 다시 Select-Object를 실행하고 나면 이 때는 개체의 형식이Selected.System.ServiceProcess.Service Controller로 바뀐다. 이 개체는 앞서의 ServiceController에서 파생된 것으로, 일부 멤버가 제거된 상태가 된다. 즉 이 개체는 Name과 Status 속성만 포함하는 것이므로, 이후로는 더 이상 DisplayName에서 이들을 정렬할 수 없다. 다음으로 Convert To-CSV를 거치고 나면 파이프라인에서는 CSV 형식의 데이터를 포함하는 System.String 개체를 포함한다. 파워셸에서는 더 이상 이들 개체를 정력하거나 선택할 수 없게 된다. 마지막으로 Out-File이 동작하면서 파이프라인에는 비워지며 결과는 파일에 기록된다.



데이터 가져오기

가져오기는 파일과 같은 외부 저장소에서 서식이 적용된 데이터를 읽어서 다시 개체로 변환하는 과정이다. 이렇게 된 개체는 파이프라인을 통해 다른 명령으로 전달해 추가적인 조작을 할 수 있다. 가져오기 프로세스의 유효성은 데이터의 형식에 달렸다. 예를 들어 CSV 파일은 단순 데이터 구조이며 복잡한 데이터 유지에 적합하지 않다. 대조적으로 XML의 경우는 복잡한 계층적 관계의 데이터를 유지하는데 적합하다. Import 동사도 Export 동사의 경우에서처럼 두 단계의 과정을 의미한다. 예를 들면 다음과 같이 파워셸 구문을 실행하면 시스템의 서비스 목록을 CSV 파일로 저장한다.

Get-Service | Export-CSV Services.csv

이제 다시 다음 명령 구문을 실행해보자.

Import-CSV Services.csv | Sort-Object Property Name,Status Descending | Select-Object First 5

이 명령은 Services.csv 파일을 읽어 부분 데이터 충실도를 갖는 원래 개체로 다시 구성하므로 Name과 같은 속성으로 내림차순으로 개체를 정력한 뒤 첫 5개의 개체를 선택한다. 가져오기는 해당 데이터가 들어있는 형식을 명령에서 알고 있어서 이 데이터에서 사용가능한 개체로 구성할 수 있음을 의미한다. 가져오기는 파일의 내용을 읽는 것과는 다르다. 다음과 같은 구문의 실행결과는 <그림 2>와 같다. 예상한 결과와 다른 이유는 Get-Content는 메모장에서 CSV 파일 내용을 살펴보는 동작을 모사하기 때문이다. 즉 내용을 이해하는 것이 아니다.

Get-Content .\Services.csv | Sort-Object -Property VM -Descending | Select-Object -First 5

방법이 전혀 없는 것은 아니다. ConvertFrom 동사를 사용하는 명령과 같이 사용한다면 원하는 결과를 얻을 수 있다. 앞의 명령을 다시 수정하여 다음과 같이 실행해보자. 그럼 <그림 3>과 같은 결과를 얻을 수 있다.

Get-Content .\Services.csv | ConvertFrom-CSV | Sort-Object -Property VM -Descending | Select-Object -First 5

column_img_1897.jpg

column_img_1898.jpg

원하는 결과를 얻는데 사용한 ConvertFrom-CSV 커맨드렛은 바로 해당 데이터를 해석하고 사용가능한 개체로 구성해 파이프라인에 넣어주기 때문이다.




Import-CSV를 단독으로 사용하는 것과 Get-Content와 ConvertFrom-CSV를 함께
사용하는 것이 동일한 결과를 보여주긴 하지만 Import-CSV를 사용할 때 동일한 결과를 더 빠르게 얻는다.



파이프라인에서 개체 컬렉션 다루기

커맨드렛의 실행 결과로 나온 개체가 컬렉션일 때도 있다. 컬렉션은 유사한 개체의 집합이다. 그렇지만 컬렉션 역시 개체이며 고유한 속성과 메서드를 갖는다. 따라서 이 속성과 메서드를 이용하면 컬렉션에서 하나 이상의 개체를 다룰 수 있다. 컬렉션이 파이프라인을 통해 흐를 때 컬렉션의 각 개체를 한 번에 하나씩 다루는 과정을 열거(Enumeration)라고 한다. 열거는 파워셸에서 원하는 동작을 수행할 수 있는 별도의 커맨드렛이 있을 때는 필요하지 않지만, 개체의 멤버 중에 원하는 메서드가 존재하지만 파워셸 커맨드렛으로 해당하는 작업을 할 수 없을 때는 열거라는 방식을 통해 개별 개체를 처리해야 한다.

열거를 수행하는 대표적인 커맨드렛은 ForEach-Object다. 여기에는 ForEach와 %라는 두 개의 별칭이 있다. ForEach-Object는 지난 연재에서 설명한 Where-Object처럼 기본 구문과 고급 구문이 있다. 기본 구문에서는 파이프라인에서 해당 명령으로 들어온 개체의 단일 메서드를 실행하거나 단일 속성을 액세스한다. 예를 들어, 다음의 구문은 e:\Test라는 폴더의 모든 파일을 암호화 하는 명령이다.

Get-ChildItem Path C:\Test\ -File | ForEach-Object MemberName Encrypt

이 구문에서 출력 개체의 멤버가 메서드라면 멤버 이름 다음에 괄호(이를테면, Encrypt())를 포함하지 않는다. 위 구문은 다음과 같이 약식으로도 작성 가능하다.

Get-ChildItem Path C:\Test\ -File | % Encrypt

열거를 기본 구문으로 다룰 때의 한계는 파이프라인을 통해 넘어온 개체에 대해 단일 멤버만 액세스하게 되어 논리 비교나 판단, 다른 명령이나 코드를 실행할 수 없다. 예를 들면, 다음과 같은 명령 구문은 사용하지 못한다.

Get-Service | Where Name like ‘s*’ and Status eq ‘Running’

이런 경우에 필요한 방법이 열거의 고급 구문이다. 고급 구문은 유연성과 기능을 더 많이 제공한다. 이 방법은 단일 개체 멤버를 액세스하지 않고 전체 스크립트를 실행할 수 있다. 앞서의 파일의 암호화 설정을 다음과 같이 고급 구문으로 작성할 수 있다.

Get-ChildItem Path C:\Test\ -File | ForEach-Object Process {$PSItem.Encrypt() }




고급 구문의 열거를 사용할 때, 메서드 이름에는 항상 여는 괄호와 닫는 괄호를 붙여야 한다.
ForEach-Object 커맨드렛에는 Process 매개면수가 있어 스크립트 블록을 받을 수 있다.
이 스크립트 블록은 파이프라인으로 들어온 각 개체에 대해 한 번씩 실행된다.
$PSItem (또는 $_)은 현재 개체를 나타낸다.
ForEach-Object를 사용하는 고급 기법의 시나리오 한 가지를 더 들자면 지정한 횟수만큼 주어진
작업을 반복해야 하는 경우다. 다음과 같은 명령 구문은 범위 연산자를 사용해 100개의 무작위 값을 얻는다
1..100 | ForEach-Object { Get-Random }
두 개의 마침표(..)가 바로 범위 연산자다. 위 명령에서 실제 정수 값은 사용되지 않는다.
100개의 개체가 ForEach-Object로 넘어가지만 스크립트 블록을 100번 실행할 뿐이다.



개체의 속성과 메서드 다루기

개체의 속성이나 메서드를 편리하게 다루기 위해서는 커맨드렛의 결과를 변수에 저장하는 것이 좋다. 파워셸에서 개체를 변수에 저장하는 구문은 다음과 같다.

$variable = object

파워셸에서 변수의 이름에는 항상 $를 붙여야 한다. 다음은 변수에 명령 구문의 출력 개체를 저장하는 예다. 이 명령은 프로세스 정보를 읽어 파워셸에 해당하는 개체를 변수에 저장한다.

$ps=Get-Process | Where-Object {$_.processname -eq "powershell"}

변수에 저장한 개체의 Handles 속성을 접근할 때는 다음과 같이 한다.

$ps.Handles

개체의 속성 값을 알아내고 이런 속성 값을 변경하여 다른 동작을 수행하려면 다시 변수에 저장한 뒤 사용하거나 직접 값을 할당하여 변경한다. 조금 전에 알아낸 파워셸 프로세스의 핸들 값을 이용해서 출력하는 구문을 다음과 같이 작성할수도 있다.

$whandle=$ps.Handles

write-host 파워셸 핸들은 $whandle이다. 개체의 멤버를 확인할 때, MemberType이 Property인 항목의Definition 열을 보면 해당 속성의 값을 읽고 변경할 수 있다면 끝에 중괄호 내에 get과 set을 표시하고 있다. 예를 들어 다음의 구문을 실행하면 <그림 4>와 같이 MaxWorkingSet 항목의 Definition 열에서 확인할 수 있다.

$ps | Get-Member

MaxWorkingSet은 해당 프로세스에서 사용할 수 있는 최대 메모리를 확인하고 설정할 수 있는 속성이다. 따라서 다음과 같이 속성 값을 변경이 가능하다.

$ps.maxworkingset=30*1024*1024

개체의 속성은 개체의 상태를 나타내지만 메서드는 개체의 동작을 나타낸다. 개체의 메서드의 사용방법은 해당 메서드에서 매개변수가 필요한지 여부에 따라 다르다. 앞서 시스템의 프로세스 정보를 읽어 그 중에서 파워셸 개체를 $ps에 저장했다. 이제 이 변수에 저장한 해당 프로세스를 중지하고자 한다면 다음 명령처럼 프로세스 개체의 멤버에 있는 kill 메서드를 이용할 수 있다.

$ps.kill()

이상으로 두 번에 걸쳐 파워셸에서 개체를 자유롭게 다루기 위해 알아야 하는 기본 개념과 핵심 커맨드렛의 사용법을 설명했다. 지금까지의 내용을 잘 따라왔다면, 이제 개체에 대해 이해하고 어떻게 다룰지 감을 잡았으리라 생각한다. 다음 시간에는 파워셸을 보다 강력한 도구로 만들어주는 스크립트 작성과 관련된 내용을 다룰 것이다.