メモ帳で開けないような数ギガバイト以上の巨大なテキストファイルから特定の行から任意の行数のテキストを抽出したいことがありました。お手軽にPowerShell でできないもんかなぁと思って作ってみましたのでこのスクリプトを覚書として記載します。

試したところ、パフォーマンスはあんまり期待できませんが、メモリは消費しなかったのである程度は使えるのではと思います。(今後、数ギガファイルからレコードを抽出したいという要件に出くわすかは別として。)

本スクリプトファイルを使用するとたとえば テキストファイルの1000万行目から1000件レコードを抽出するようなことができるようになります。

64bit版の秀丸エディタでは数ギガのテキストファイルでも開けるそうです。

ちなみに、ファイルの先頭から任意の行数取得する場合は、今回紹介するスクリプトファイルを使用しなくても、 Get-Content コマンドレットに -TotalCount オプションを指定するだけで実現できます。

1. PowerShell スクリプトファイルの作成

Skip-Record.ps1 ファイルを作成し、次のようにスクリプトを記載します。スクリプトでは、第一引数にスキップする行数を指定します。第二引数に取得する行数を指定します。

param([int] $skip = $(throw "スキップ行数を指定してください。"), [int] $take = $(throw "取得行数を指定してください。"))

begin{
 $count = 0
}
process{
  $count++;
  if($count -gt $skip -and $count -lt $skip + $take){
     $_;
  }elseif($count -gt $skip + $take){
    break;
  }
}
end{
 $count;
}

スクリプトでは、$skip + $take 行数を超えた場合 break 文を実行して パイプラインを停止することで必要以上の行数を読み込まないようにしています。

スクリプトファイルの準備は完了です。

2.使い方

使用方法は簡単です。下記コマンドでは、 LargeData.txt というファイルからレコードを抽出し Skip-Record.ps1 ファイルは 1000000 行スキップして 1000 行 とり出しています。

Get-Content .\LargeData.txt  | .\Skip-Record.ps1 1000000 1000

動作確認したところ、ファイルの読み込みは Get-Content を使用しているので先頭からレコードを読み出しますが、パイプライン処理を使用するのでメモリは消費しませんでした。必要な行数を読み込んだあとパイプライン処理を終了するので、ファイルの末尾まで読み込まず処理が終了します。

3.まとめ

説明は以上です。誤り指摘点などありましたらご連絡ください。

Skipするスクリプト書いてて思ったのですが PoweShellってUnixのtail コマンドに当たるもコマンドがないような。Windows リソースキットには tail コマンドあるみたいなのでそっちを使えってことかもしれませんが。