目的
PowerShellのコンソールで使う grep のようなテキスト検索用のツール(関数)を作りました。マッチした部分をハイライト表示できるのが特長です。以前に投稿したものは複数のファイルを検索対象としていましたが、こちらは主にパイプ経由で入力されたテキストを検索対象としています。
使用方法
① PS> コマンド | hgrep 検索文字列
あるいは
② PS> hgrep 検索文字列 -io (gc ファイルパス)
② の代わりに ① でコマンドを Get-Content にすることでもファイルの中身の検索ができます。
例) 二重引用符で囲まれた文字列を検索
行単位検索: PS> gc ファイルパス | hgrep '".*?"'
複数行検索: PS> gc ファイルパス -raw | hgrep '"[\S\s]*?"'
又は
PS> gc ファイルパス -raw | hgrep '(?s)".*?"'
下記のコマンドライン引数が利用可能です。
- [-Pattern]
- 検索文字列(正規表現)を指定します(必須)。
- -IgnoreCase, -i
- 大文字・小文字を区別しません。
- -InputObject
- 入力オブジェクトを指定します。既定値は Null(パイプ入力)。
- -Group, -g
- キャプチャグループの番号または名前を指定します。既定値は "0"。
- -Narrow, -w
- 検索前に全角数字、全角カナ等を半角に変換します。
- -Number, -n
- 行番号を表示します。
- -Passthru, -p
- マッチしない行も含めて全ての行を出力します。
- -SimpleMatch, -s
- 正規表現を使わず単純文字列検索を行います。
- -BackgroundColor, -bc
- マッチ箇所の背景色を指定します。既定値は "White"。
- -CapturegroupColor, -cc
- マッチ箇所(キャプチャグループ)の文字色を指定します。既定値は "Red"。
- -ForegroundColor, -fc
- マッチ箇所の背景色を指定します。既定値は "Blue"。
実行例
コード
プロファイル設定(\$profile のパスが示すファイル)に下記の関数定義を加えるか、拡張子 .psm1 のファイルに保存して \$PSModulePath に含まれるいずれかのパスのいずれかの下に
hGrep
└hGrep.psm1
のフォルダ構造で保存した後、PowerShellコンソールを起動して hgrep とタイプして呼び出すことができます1(あるいはもっと簡単に Install-Module hGrep
を実行することでもインストール可能)。
<#
.SYNOPSIS
A grep-like tool with a color highlighting feature.
.DESCRIPTION
This function searches for text patterns in input strings.
If input is an object, it is converted to a string prior to processing.
Matched characters are highlighted.
'(some command) | Select-MatchedString -Pattern <regex>'
is similar to
'(some command) | Output-String -Stream | Select-String -Pattern <regex> -AllMatch -CaseSensitive'
with PowerShell 7.X, in which Select-String cmdlet has a highlighting feature.
.PARAMETER Pattern
Specifies the text patterns to find. Type a string or regular expression.
If you type a string, use the SimpleMatch parameter.
.PARAMETER BackgroundColor
Specifies the background color for matches. (Alias: -bc)
The default value is "Blue".
.PARAMETER CapturegroupColor
Specifies the foreground color for capture-group matches. (Alias: -cc)
The default value is "Red".
.PARAMETER ForegroundColor
Specifies the foreground color for matches. (Alias: -fc)
The default value is "White".
.PARAMETER Group
Specifies the name or number of capture group. (Alias: -g)
The default value is "0".
.PARAMETER ECMAScript
Enables ECMAScript-compliant behavior. (Alias: -e)
.PARAMETER IgnoreCase
Makes matches case-insensitive. By default, matches are case-sensitive. (Alias: -i)
.PARAMETER InputObject
Specifies the text to be searched. (Alias: -io)
.PARAMETER PassThru
Outputs all lines, including ones that do not match. (Alias: -p)
.PARAMETER Narrow
Converts wide characters into narrow ones internally. (Alias: -n)
Useful when you don't want to distinguish between narrow and wide characters.
.PARAMETER SimpleMatch
Uses a simple match rather than a regular expression match. (Alias: -s)
.NOTES
Author: earthdiver1
Version: V1.03
Licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
#>
Function Select-MatchedString {
[Alias('hGrep')]
Param(
[Parameter(Mandatory=$True)][String]$Pattern,
[Alias("g")][String]$Group = "0",
[Alias("e")][Switch]$ECMAScript,
[Alias("i")][Switch]$IgnoreCase,
[Alias("w")][Switch]$Narrow,
[Alias("n")][Switch]$Number,
[Alias("p")][Switch]$PassThru,
[Alias("s")][Switch]$SimpleMatch,
[Alias("bc")][ConsoleColor]$BackgroundColor = "Blue",
[Alias("cc")][ConsoleColor]$CapturegroupColor = "Red",
[Alias("fc")][ConsoleColor]$ForegroundColor = "White",
[Parameter(ValueFromPipeline=$True)][Alias("io")][PSObject]$InputObject
)
Begin {
try {
if ( -not $Pattern ) { break }
if ( $Narrow ) {
Add-Type -AssemblyName "Microsoft.VisualBasic"
$Pattern = [Microsoft.VisualBasic.Strings]::StrConv($Pattern,[Microsoft.VisualBasic.VbStrConv]::Narrow)
}
if ( $SimpleMatch ) { $Pattern = [regex]::Escape( $Pattern ) }
if ( $Number ) {
$line = 0
$width = $host.UI.RawUI.BufferSize.Width - 7
} else {
$width = $host.UI.RawUI.BufferSize.Width - 1
}
$regexOptions = "Compiled"
if ( $ECMAScript ) { $regexOptions += ", ECMAScript" }
if ( $IgnoreCase ) { $regexOptions += ", IgnoreCase" }
$Regex = New-Object Text.RegularExpressions.Regex $Pattern, $regexOptions
$process_block = {
Process {
$line++
$i = 0
if ( $Narrow ) { $_ = [Microsoft.VisualBasic.Strings]::StrConv($_,[Microsoft.VisualBasic.VbStrConv]::Narrow) }
$match = $Regex.Match($_,$i)
$m = $match.Groups[$Group]
if (-not $Passhru -and -not $m.Success) { return }
if ( $Number ) { Write-Host $("{0,5}:" -F $line) -NoNewline }
if ( $Group -eq "0" ) {
while ($m.Success) {
if ( $m.Index -ge $_.Length ) { break }
if ( $m.Length -gt 0 ) {
Write-Host $_.SubString($i, $m.Index - $i) -NoNewline
Write-Host $m.Value -BackgroundColor $BackgroundColor -ForegroundColor $ForegroundColor -NoNewline
$i = $m.Index + $m.Length
} else {
Write-Host $_.SubString($i, $m.Index - $i + 1) -NoNewline
$i = $m.Index + 1
}
$m = $Regex.Match($_,$i).Groups[0]
}
} else {
while ( $m.Success ) {
if ( $m.Index -ge $_.Length ) { break }
$m0 = $match.Groups[0]
if ( $m0.Length -gt 0 ) {
Write-Host $_.SubString($i, $m0.Index - $i) -NoNewline
Write-Host $_.SubString($m0.Index, $m.Index - $m0.Index) `
-BackgroundColor $BackgroundColor -ForegroundColor $ForegroundColor -NoNewline
Write-Host $m.Value -BackgroundColor $BackgroundColor -ForegroundColor $CapturegroupColor -NoNewline
$i = $m0.Index + $m0.Length
$ii = $m.Index + $m.Length
Write-Host $_.SubString($ii, $i - $ii) `
-BackgroundColor $BackgroundColor -ForegroundColor $ForegroundColor -NoNewline
} else {
Write-Host $_.SubString($i, $m0.Index - $i + 1) -NoNewline
$i = $m0.Index + 1
}
$match = $Regex.Match($_,$i)
$m = $match.Groups[$Group]
}
}
Write-Host $_.SubString($i)
}
}
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Out-String',[System.Management.Automation.CommandTypes]::Cmdlet)
$wrappedCmdParameters = @{}
if ( $PSBoundParameters.ContainsKey("InputObject") ) { $wrappedCmdParameters.Add("InputObject",$InputObject) }
$wrappedCmdParameters.Add("Stream", $True)
$wrappedCmdParameters.Add("Width", $width)
$scriptCmd = {& $wrappedCmd @wrappedCmdParameters | & $process_block }
$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
$steppablePipeline.Begin($PSCmdlet)
} catch {
throw
}
}
Process {
try {
$steppablePipeline.Process($_)
} catch {
throw
}
}
End {
try {
$steppablePipeline.End()
Remove-Variable Regex
} catch {
throw
}
}
}
Export-ModuleMember -Function Select-MatchedString -Alias hGrep
備考
- オブジェクト型の入力データは検索前に文字列型に変換されます。
- マッチ箇所の背景色は、PowerShellのコンソールの背景色と同じ DarkMagenta を指定(
-bc DarkMagenta
)すると目立たなくなります。キャプチャグループを指定する場合に、マッチした箇所がより確認しやすくなります。例)PS> gc ファイルパス | grep '"(.*?)"' -g 1 -bc DarkMagenta
- 6番目のストリームをリダイレクトして grep 関数の出力をファイルに保存した場合、マッチ箇所のハイライト処理の影響で体裁が崩れます。ファイルに出力したい場合は、標準のコマンドレットを利用して以下のようにしてください。(Select-String コマンドレットは既定では大文字・小文字の区別をしません。区別したい場合は、sls に
-CaseSensitive
を指定します。)
PS> コマンド | oss | sls 検索文字列 > 出力ファイル名
- あるいは最初から grep にハイライトなんて要らないという方は、以下の関数を定義するとよいかも知れません。
Function grep{ $Input | oss | sls $args }