PowerShell grepみたいなコマンドレット3つ
1.はじめに
Linuxユーザならgrepってかなりの頻度で使うのではないでしょうか? パイプでつなげて、コマンド結果からほしい情報だけを絞り込むために使うと思う。
Get-Aliasの実行結果は以下の通りだが、これのcatに関する情報だけをgrepしようと考えた。
PS C:\Users\hisabo> Get-Alias CommandType Name Version Source ----------- ---- ------- ------ Alias % -> ForEach-Object Alias ? -> Where-Object Alias ac -> Add-Content Alias asnp -> Add-PSSnapin Alias cat -> Get-Content (以降、略)
PowerShell初心者の私は、PowerShellにおけるgrepはSelect-Stringというコマンドレットだということを鵜呑みにして、こんな使い方をした。
PS C:\Users\hisabo> Get-Alias | Select-String -Pattern "cat" cat
あれ? Get-Aliasのcat行だけが表示されるものと期待していたのだが、そうはならなかった。
これを切っ掛けに、PowerShellにおけるgrepってどうやるの?ということを調べ始めたところ、PowerShellには情報を絞り込むためコマンドレットが(たぶん)3つあることが分かったのでまとめることにした。
2.環境
PowerShellのバージョンは以下の通り。
PS C:\Users\hisabo> $PSVersionTable Name Value ---- ----- PSVersion 5.1.18362.752 ・・・以下、略・・・
3.目指すところ
- Where-Object の使い方を覚える
- Select-Object の使い方を覚える
- Select-String の使い方を覚える
4.やってみよう
とても大切なことなので初めに書いておくが、Get-Aliasコマンドレットは実行結果をテキストで返却してきている訳ではないということを理解しておく必要がある。実行結果はオブジェクト配列(?)という形で返却されてきているのだ(たぶん)。オブジェクトとはデータ(プロパティ)と手続き(メソッド)のカタマリ。オブジェクト配列とはその羅列。このことを理解していると、以下の検証が分かりやすいと思う。
4.1 Where-Object
1つ目のWhere-Objectは、オブジェクト版のgrepと考えていい。
Where-Objectの簡単な例
Where-Objectはパイプで受け取ったオブジェクト配列を絞り込む用途で使う。使い方は、以下のような感じ。
PS C:\Users\hisabo> Get-Alias | Where-Object{ $_.Name -Like "cat"} CommandType Name Version Source ----------- ---- ------- ------ Alias cat -> Get-Content
Get-Aliasの実行結果のオブジェクト配列を受け取り、Nameプロパティが"cat"の条件に合致するものをWhere-Objectで返却(ここでは出力)している。
Where-ObjectをForeach-Objectで実現する
察しの良い方ならわかると思うが、これはForEach-Object(Aliasは%)で以下のように同じことが実現できる。
PS C:\Users\hisabo> Get-Alias | %{If($_.Name -like "cat"){$_}} CommandType Name Version Source ----------- ---- ------- ------ Alias cat -> Get-Content
Where-Objectは何を返すコマンドレットなのか?
さて、Where-Objectはテキストを返しているの?オブジェクト配列を返しているの?を実験してみた。
PS C:\Users\hisabo> Get-Alias | Where-Object{ $_.Name -Like "cat"} | %{$_.Definition + " -> " + $_.Name} Get-Content -> cat
プロパティが指定できるから、Where-Objectはオブジェクト配列を返しているようだ。
Where-Objectは複雑な条件をこなせるのか?
もう少しだけ実験。Where-Objectは比較演算子、論理演算子を使った複雑な条件を作りこめるのか?
PS C:\Users\hisabo> Get-Alias | Where-Object{ $_.Name -Like "cat" -or $_.Name -Like "echo"} CommandType Name Version Source ----------- ---- ------- ------ Alias cat -> Get-Content Alias echo -> Write-Output
ということで、Where-Object内では、Ifと同じように論理演算子を使い、複雑な条件を指定することができる。また、Ifで使われる-eqや-Likeをはじめとした様々な比較演算子を使うことができるようだ。
Get-Aliasの結果をgrepするならオプション使ってもできる
今まで、Get-Aliasの結果を絞り込みしようと頑張ってきたが、Where-Objectを使わずともGet-AliasのNameオプションを使って以下のようにすることもできることを後で知った(笑)。
PS C:\Users\hisabo> Get-Alias -Name cat CommandType Name Version Source ----------- ---- ------- ------ Alias cat -> Get-Content
4.2 Select-Object
2つ目のSelect-Objectは、パイプで渡されたオブジェクト配列のそれぞれのオブジェクトのプロパティを選択するような使い方が多いようだ。データベースのSELECT句に近いイメージだ。
Select-Objectの簡単な例
Get-AliasのNameプロパティだけを選択して表示させるような使い方ができる。以下のように。
PS C:\Users\hisabo> Get-Alias | Select-Object -Property Name Name ---- % ? ac asnp cat cd CFS chdir clc clear clhy (以降、略)
「SELECT obj.Name As Name From `Get-Alias` As obj」みたいな感じ。
Select-ObjectをForeach-Objectで実現する
概ね、同様のことがForeach-Objectで以下のように実現できる。
PS C:\Users\hisabo> Get-Alias | %{$_.Name} % ? ac asnp cat cd CFS chdir clc (以降、略)
Select-Objectは何を返すコマンドレットなのか?
さて、Select-Objectはテキストを返しているの?オブジェクト配列を返しているの?を実験してみた。
PS C:\Users\hisabo> Get-Alias | Select-Object -Property Name,Definition | %{$_.Name + " -> " + $_.Definition} % -> ForEach-Object ? -> Where-Object ac -> Add-Content asnp -> Add-PSSnapIn cat -> Get-Content cd -> Set-Location CFS -> ConvertFrom-String chdir -> Set-Location clc -> Clear-Content clear -> Clear-Host clhy -> Clear-History cli -> Clear-Item clp -> Clear-ItemProperty cls -> Clear-Host clv -> Clear-Variable (以降、略)
どうやら、オブジェクト配列を返しているみたいだ。
4.3 Select-String
3つ目のSelect-Stringはオブジェクトを相手にするのではなく、テキストを相手にするコマンドレット。bashのgrepに一番近い。
Select-Stringの簡単な例1(テキストファイルをGrep)
PS C:\Users\hisabo> Get-Alias > Get-Alias.txt ・・・Get-Aliasの結果をテキストファイルに出力 PS C:\Users\hisabo> Get-Content Get-Alias.txt ・・・内容確認 CommandType Name Version Source ----------- ---- ------- ------ Alias % -> ForEach-Object Alias ? -> Where-Object Alias ac -> Add-Content Alias asnp -> Add-PSSnapin Alias cat -> Get-Content Alias cd -> Set-Location Alias CFS -> ConvertFrom-String 3.1.0.0 Microsoft.PowerShell.Utility Alias chdir -> Set-Location Alias clc -> Clear-Content (以降、略)
上記のようなテキストファイルを準備した。
PS C:\Users\hisabo> Select-String -Path Get-Alias.txt -Pattern "cat" ・・・テキストファイルをGrep Get-Alias.txt:8:Alias cat -> Get-Content Get-Alias.txt:9:Alias cd -> Set-Location (中略) Get-Alias.txt:109:Alias pwd -> Get-Location Get-Alias.txt:142:Alias sl -> Set-Location
何故か行間に改行が入ってしまうが、一応、テキストファイルのgrepができている。
Select-Stringは何を返すコマンドレットなのか?
PS C:\Users\hisabo> $a = Select-String -Path Get-Alias.txt -Pattern "cat" PS C:\Users\hisabo> $a.Count 8
配列の個数が8らしい。
PS C:\Users\hisabo> $a[0].Line Alias cat -> Get-Content
配列の1つ目のLineプロパティの内容をこんな感じ。Select-Stringはオブジェクト配列を返してきているみたいだ。
PS C:\Users\hisabo> Select-String -Path Get-Alias.txt -Pattern "cat" | Select-Object -Property Line Line ---- Alias cat -> Get-Content Alias cd -> Set-Location Alias chdir -> Set-Location Alias gl -> Get-Location Alias popd -> Pop-Location Alias pushd -> Push-Location Alias pwd -> Get-Location Alias sl -> Set-Location
Select-Stringの結果をSelect-Objectで処理できるので、どうやらSelect-Stringはオブジェクト配列を返すコマンドレットのようだ。
Select-Stringの簡単な例2(コマンドの結果をGrep)
Select-Stringは先に書いたようにテキストを相手にするコマンドレット。別のコマンドの結果をSelect-Stringしたかったら、別のコマンドの結果をテキストストリームに変換する必要がある。コマンド結果をテキストストリームに変換するコマンドがある。
PS C:\Users\hisabo> get-alias | out-string -stream CommandType Name Version Source ----------- ---- ------- ------ Alias % -> ForEach-Object Alias ? -> Where-Object Alias ac -> Add-Content Alias asnp -> Add-PSSnapin (略)
out-string -streamはコマンド結果をテキストストリームに変換してくれる。これをカマすことによりSelect-Stringでgrepできる。
PS C:\Users\hisabo> Get-Alias | Out-String -stream | Select-String "cat" Alias cat -> Get-Content Alias cd -> Set-Location Alias chdir -> Set-Location Alias gl -> Get-Location Alias popd -> Pop-Location Alias pushd -> Push-Location Alias pwd -> Get-Location Alias sl -> Set-Location
こんな風にget-aliasコマンドレットの結果を"cat"を含む行だけをGrepして表示することができる。
終.獲得した知識
- Where-Objectコマンドレットの使い方
- Select-Objectコマンドレットの使い方
- Select-Stringコマンドレットの使い方
- Out-String -streamでコマンドの結果をテキストストリームに変換できること