ファイルの内容を検索して一覧表示

作業をしていて、適当なgrepコマンドが欲しくなったのでPowerShellで書いてみた。

###############################################################################
# 関数名:
#       Grep-Content (grep)
# 説明:
#       指定した文字列を含むファイルを検索して、結果を表示します。
# 引数;
#       $text       :   検索する文字列
#       $pattern    :   検索するファイルのパターン
#       $recurse    :   サブディレクトリも対象にするか
###############################################################################
function Grep-Content([string]$text, [string]$pattern, [switch]$recurse) {
    $curPath = (Get-Location).Path
    Get-ChildItem -recurse:$recurse -exclude "*.dll,*.exe" | where { !$_.PSIsContainer -and $_.Name -like $pattern } | foreach {
        $file = $_          # ファイル
        $lineNumber = 1     # 行番号
        Get-Content $_ | foreach {
            $pos = $_.IndexOf($text)
            if($pos -ne -1) {
                # ヒットした箇所を色分けして表示
                Write-Host -noNewLine -foreGroundColor Green ("{0} => {1}行目 : " -f $file.FullName.Replace($curPath, ""), $lineNumber)
                Write-Host -noNewLine $_.Substring(0, $pos).TrimStart()
                Write-Host -noNewLine -foreGroundColor Yellow $text
                Write-Host $_.Substring($pos + $text.Length)
            }
            $lineNumber++
        }
    }
}
Set-Alias grep Grep-Content

ヒットした箇所を「Write-Host」で色分けして表示しているところがミソ。かなり結果が見やすくなった。でもこれでやると標準出力に吐かれないから、ファイルにリダイレクトができない、まぁええか。
「Get-ChildItem」への「-recurse」オプションの引渡しをどうやってやろうかと考えていて色々調べていたら、「switch」型の引数でできることがわかった。この値を「-recurse:$recurse」でオプションをONにできる。

あと、「Get-ChildItem」は「-recurse」オプションをONにすると「-include」でしかファイル名のフィルタリングができなくて、ONとOFF時での切り分けがめんどくさかったので、その後の「where」でフィルタリングした。
ディレクトリかどうかはオブジェクトの型が「FileInfo」かどうか「PSIsContainer」プロパティで見分けた。

PowerShellは最高におもしろい!!