ログからキーワードを抽出して、ソートして、同じものを切り捨てる 壱
コマンドプロンプトでは、よくやるコマンドのテンプレート
ログファイルに対してよくやることは、たぶん以下の作業
- 履歴をファイルをまとめて1つに集約
- ファイルの中身を出力
- ファイルの中身からキーワードを含む行を抽出
- 抽出した内容をソート
ログの場合、タイムスタンプがあるし、そもそも昇順
しかし、タイムスタンプ部をスキップして、メッセージだけをソートしたいことはある - ソートした中身から重複するものを切り捨てる
Windowsには該当コマンドなし
Unix系にはuniqコマンドがある(要ソート)
いい加減、MS-DOSから脱却したいのにいつまでも、この操作をMS-DOSでやっているので、まじめにPowerShellスクリプトを考えようと思う。
複数のファイルを連結して、1つのファイルに集約
コマンドプロンプトの場合
最初の元凶がここ。スマートな方法があるはず。今まで10個の履歴ファイルを一生懸命書いて連結していたけど、もう飽きた。
copy [ファイル1] + [ファイル2] + [ファイル3] [集約するファイル名]
シェル系
gitをインストールすると、WindowsでもUnixコマンドが使えるので便利だし、任意のフォルダからエクスプローラの右クリックでBash起こせるから、こっちを覚えるべきかもしれないけど、それはまたの機会に。
# 連結するファイル名にワイルドカードを使うと一気に連結 # 順番はきっとASCII順 履歴番号ありとなしで順番が意図しない形になるかもしれない # Output.log.* # 順番が重要であるなら、列挙して最後にリダイレクトする。 # 最後にリダイレクトでファイル出力するのを忘れずに cat [連結するファイル名] > [集約するファイル名] cat [ファイル1] [ファイル2] [ファイル3] > [集約するファイル名]
PowerShell
まずはネットで、やり方を調べてみると以下の3つが上がってきた。*-Contentで出力するのが正統派に思えてきたけど、リダイレクトもパイプラインとしては王道なので、テンプレート検討としては悩むところ。
Get-Contentで渡すワイルドカードでは、"*.log.*"を指定した場合、"hogehoge.log"は拾ってくれなかったのは困りもの。
Get-ChildItem -File -Filter ["ワイルドカード"] | Get-Content | Add-Content [集約するファイル名] Get-Content [ワイルドカードで指定するファイル名] > [集約するファイル名] Get-Content [ファイル名1], [ファイル名2], [ファイル名3] | Set-Content [集約するファイル名]
ちなみに私の職場のログファイルは…
hogehoge.log
hogehoge.log.01
hogehoge.log.02
hogehoge.log.03
となっていて、ちと扱いが辛い。逆順にする必要もある。しかし、これは以下のやり方で解決できた。
これで、ファイル名を逆順に出力させて1つのファイルに集約できる。後はリダイレクトか、*-Contentで出力する。
Get-ChildItem -File -Filter "*.log.*" | Sort-Object -Descending
PS C:\Users\USER\Desktop\work> Get-ChildItem -file -filter "*.log.*" | Sort-Object -Descending ディレクトリ: C:\Users\USER\Desktop\work Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2020/09/12 16:38 16 output.log.03 -a---- 2020/09/12 16:37 16 output.log.02 -a---- 2020/09/12 16:37 16 output.log.01 -a---- 2020/09/12 16:37 16 output.log
■コマンドプロンプトで最初に叩く、ログの集約作業はこれで行こう。
Get-ChildItem -File -Filter "*.log.*" | Sort-Object -Descending | Get-Content > [出力ファイル名]
必要なキーワードで抽出する。
MS-DOS
find.exeは昔からの人がつい、手なりで叩いてしまいますが、今は正規表現も使えるfindstr.exeが本流なのでしょう。正規表現のリファレンスはここ(@IT)でも良いかと。
type [入力ファイル名] | find "キーワード名" type [入力ファイル名] | findstr "キーワード名" find "キーワード名" < [入力ファイル名] findstr "キーワード名" < [入力ファイル名]
シェル系
grepは検索の王道なので説明するまでもなく…
cat [入力ファイル名] | grep "キーワード名" grep "キーワード名" < [入力ファイル名]
PowerShell
正規表現も利用したいですし、Select-Stringを使いましょう。
Get-Content -Path <入力ファイル名> | Select-String -Pattern '正規表現'
ここで、単に ERROR
の文字を抽出するのであれば、
Get-Content [入力ファイル名] | Where-Object { $_ -like "*ERROR*" } Get-Content [入力ファイル名] | Where-Object { $_ -match "ERROR" }
も、ありかもしれません。しかし、シンプルなコードにするなら、Select-Stringがよいと思われます。
データのソートに関しては、ログに関しては桁位置がガタガタ(スレッド名の設定を%tにしてしまったので3~5桁でそろわない)なので、まずここをやっつけなければなりませんが、このネタだけで長くなりそうです。
ということで、次回の講釈で。