PR

【Windows Powershell】特定の文字列を含むファイルの検索方法

OSS開発

Windowsを操作していて、こんな経験がありませんか?

あのファイルが必要なのに、どこにあるか分からない!」「ひとつひとつファイルを開いて確認するのは実質無理だ

この記事では、こうしたファイル検索に関する問題を解決するために、「現在のディレクトリ以下を再帰的に検索し、指定した文字列を含むファイルの一覧を出力する方法」を解説します。

WordPressブロガーの方必見! 外出先でもブログ執筆作業がはかどる、 Ankerの大容量モバイルバッテリー をご紹介します。

特定の文字列を含んだファイルを一覧表示する方法

下記のスクリプトをコピペしてください。ファイル名はfindfiles.ps1とします。

PowerShell
# findfiles.ps1
Param(
    $arg # 引数
)
try {
    $ErrorActionPreference = "Stop"
    $count = 0
    $files = Get-ChildItem -Recurse -File
    $totals = ($files | Measure-Object).Count
    $files | ForEach-Object {
        $count += 1
        $per = ($count/$totals)*100
        $rtime = $totals - $count 
        Write-Progress -Activity "Progress: " -Status "$per% Complete" -PercentComplete $per -secondsRemaining $rtime
        if (Get-Content $_.FullName | Select-String -Pattern "$arg" -Quiet) {
            Write-Host "ファイル名: $($_.FullName)"
        } 
    }
} catch {
    Write-Host $_ -ForegroundColor "Red" # catch内の例外情報は、「$_」変数でアクセスできる。
} finally {}

上記のスクリプトを、PATHが通っているフォルダに保存します。

「PATH通し」に関して詳細を知りたい方は、以下の記事をご参照ください。

使い方

Powershellを立ち上げ、findfiles "文字列"とします。すると、現在ディレクトリ以下全てを検索し、指定した文字列が記述されているファイル全てを一覧表示します。

PowerShell
PS C:\Users\ユーザー名> findfiles "文字列"

使用例

試しに、現在「テスト」フォルダにいるとします。
テストフォルダの中には、2つのフォルダがあり、さらにそれぞれのフォルダの中に3つのフォルダがあります。それら全てのフォルダに「test.txt」が存在し、その内2つのファイルには「当たり」と書かれているとします。

以下のような構造です。

PowerShell
PS C:\Users\ユーザー名\テスト> tree
.
├── test.txt
├── test01
│   ├── 01
│   │   └── test.txt
│   ├── 02
│   │   └── test.txt
│   ├── 03
│   │   └── test.txt
│   └── test.txt
└── test02
    ├── 01
    │   └── test.txt
    ├── 02
    │   └── test.txt
    ├── 03
    │   └── test.txt
    └── test.txt

このようにサブフォルダがいくつも存在する構造では、ファイルの中身を一つ一つ調べるのも一苦労します。
そこで、ターミナル上でfindfiles "当たり"と入力しましょう。

すると、当たりが書かれたファイルパスが一覧表示されました。

PowerShell
PS C:\Users\ユーザー名\テスト> findfiles "当たり"
ファイル名: C:\Users\ユーザー名\テスト\test01\test.txt
ファイル名: C:\Users\ユーザー名\テスト\test01\03\test.txt

Powershellスクリプトの構造解説

このスクリプトがどんな構造になっているのか解説します。

1.引数

まずParam()とは、Powershellで引数を設定するコードです。

ここに引数を設定すると、./hoge.ps1 引数のように引数をスクリプトに渡せるようになります。

PowerShell
Param(
    $arg # 引数
)

2.例外処理

try{} catch{} finally{}は例外処理のコードです。$ErrorActionPreference = "Stop"は、エラーが発生した際に、強制的に処理を止めるための記述です。

PowerShell
try {
    $ErrorActionPreference = "Stop"
    処理
} catch {

    例外処理
} finally {}

3.処理

以下が、「現在ディレクトリ以下を全て検索し、指定した文字列を含んだファイル一覧を出力する方法」のコードです。

PowerShell
$files = Get-ChildItem -Recurse -File
$totals = ($files | Measure-Object).Count
$files | ForEach-Object {
    if (Get-Content $_.FullName | Select-String -Pattern "$arg" -Quiet) {
        Write-Host "ファイル名: $($_.FullName)"
    } 
}

1つずつ解説します。

  1. $files = Get-ChildItem -Recurse -File
    • この行では、Get-ChildItemコマンドレットを使用して、指定されたディレクトリ内のファイルの一覧を取得しています。-Recurseフラグは、サブディレクトリ内のファイルも含めて再帰的に検索することを指示します。-Fileフラグは、ファイルのみを取得することを示しています。取得したファイルは$filesという変数に格納されます。
  2. $totals = ($files | Measure-Object).Count
    • この行では、取得したファイルの数を数えます。Measure-Objectコマンドレットは、渡されたオブジェクトのプロパティを測定し、統計情報を提供します。.Countは測定されたオブジェクトの数を返します。
  3. $files | ForEach-Object { ... }
    • この行は$filesに含まれる各ファイルに対して処理を行います。ForEach-Objectコマンドレットは、配列内の各オブジェクトに対して指定された処理を実行します。各ファイルに対して実行される処理は、波括弧 {} 内に記述されています。
  4. if (Get-Content $_.FullName | Select-String -Pattern "$arg" -Quiet) { ... }
    • この行では、ファイル内のコンテンツを取得し、特定のパターンに一致するかどうかを確認しています。Get-Contentコマンドレットは、ファイルの内容を取得します$_は現在のファイルオブジェクトを表し、FullNameプロパティはファイルのフルパスを返します。Select-Stringコマンドレットは、指定されたパターンに一致する行を選択します-Patternフラグは検索するパターンを指定し、-Quietフラグは一致が見つかった場合に真を返します。if文の条件式が真の場合は、波括弧 {} 内のコードが実行されます。
  5. Write-Host "ファイル名: $($_.FullName)"
    • この行は、一致したファイルのフルパスを出力します。Write-Hostコマンドレットは、指定した文字列をコンソールに表示します。$($_.FullName)は、現在のファイルのフルパスを表します。

一番のポイントは、「Get-Contentコマンドレット」と「Select-Stringコマンドレット」です。
この2つを組み合わせることで、ファイルの中身に特定の文字列があるかどうかを真偽で判定することができます。

4.進捗バー

残りのコードは「処理の進捗」を表示するためのものです。先程の「テスト」フォルダではファイル数が少ないため、実行しても進捗バーは一瞬で消えますが、数千から数万のファイルを抱えるフォルダで使用する場合は、非常に役立つと思います。

PowerShell
Write-Progress -Activity "Progress: " -Status "$per% Complete" -PercentComplete $per -secondsRemaining $rtime

処理の進行状況を表示するためにWrite-Progressコマンドレットが使用されています。-Activityフラグは進行状況ウィンドウに表示されるアクティビティ名を指定し、-Statusフラグは進行率のステータスを示します。-PercentCompleteフラグは進行率をパーセンテージで指定し、-secondsRemainingフラグは残りの秒数を指定します。

まとめ

この記事では、現在のディレクトリ以下を再帰的に検索し、指定した文字列を含むファイルの一覧を出力する方法を解説しました。

findfiles.ps1を使用すれば、findfiles "文字列"という簡単なコマンドで、指定した文字列が含まれるファイルのパス一覧を取得できます。

特に、数千から数万のファイルを持つプロジェクトでの使用に役立つかと思われます。

タイトルとURLをコピーしました