PowerShellでgrep -oみたく正規表現にマッチしたところだけ抜き出す

正規表現にマッチした部分だけを抜き出したい みたいな状況は結構ある気がします。 適当なファイルからURLっぽいところだけ取り出したいとか、HTMLから特定のタグを取得したいとか。

例として、ここでは以下のファイル(っていうかメール?)からメールアドレス取り出してみます。 簡略化のために、メールの正規表現は[-_.a-zA-Z0-9]+@[-_.a-zA-Z0-9]+で良いということにします。

Subject: hello world!
To: alice@example.com
From: Bob@example.com

hello alice!!

Linuxの場合

Linuxであれば、以下のようなコマンドで正規表現マッチを取り出すことが出来ます。

$ grep -io '[-_.a-z0-9]\+@[-_.a-z0-9]\+' ./input.txt
alice@example.com
Bob@example.com

-oオプションを付けるとマッチ部分だけ出力されます。 ついでに-iを付けて、大文字小文字を無視するようにしています。

PowerShellの場合

PowerShellの場合、grepコマンドに相当するSelect-Stringというコマンドがあるようです。 slsってエイリアスもあるっぽい。

> Get-Content .\input.txt | Select-String '[-_.a-z0-9]+@[-_.a-z0-9]+'
To: alice@example.com
From: Bob@example.com

単純に使うとこんな感じ。デフォルトで大文字小文字を無視するようになっています。

残念ながら、このコマンドには-oに相当する機能がありません。 その代わりに出力がオブジェクト(構造体? クラス?)になっているので、ForEach-Objectでマッチ部分を取り出すことが出来ます。

> Get-Content .\input.txt | Select-String '[-_.a-z0-9]+@[-_.a-z0-9]+' | ForEach-Object { $_.Matches.Value }
alice@example.com
Bob@example.com

うーん、長い。 省略形を使うと以下のような感じになります。

> cat .\input.txt | sls '[-_.a-z0-9]+@[-_.a-z0-9]+' | % { $_.Matches.Value }
alice@example.com
Bob@example.com

うーん、わかりづらい。


参考: analog command grep -o in Powershell - Stack Overflow