PowerShell テキストファイル(とりわけログファイル)をGrepして、欲しい情報だけを得る
1.はじめに
レガシーシステムのログファイル(テキストファイル)をGrepしたいって思う機会があったのでメモ。
2.環境
PowerShellのバージョンは以下の通り。
PS > $PSVersionTable Name Value ---- ----- PSVersion 5.1.19041.610 ・・・以下、略・・・
3.目指すところ
- 「日時+ログコメント」×複数行のテキストファイルから本日分のログだけを表示する
- 「日時+特定のログコメント」が存在するかを確認する
4.やってみよう
話を単純にするためにログファイルはUTF8、改行はCRLFのテキストファイルとする(notepadの標準)。 また、テキストファイルの内容は以下のような内容とする。
PS > Get-Content -Path "C:\temp\hoge.log" 2020/12/04 16:00:00.123 START 2020/12/04 16:00:01.678 A 2020/12/04 16:00:02.194 B 2020/12/04 16:00:05.998 END 2020/12/05 16:00:00.123 START 2020/12/05 16:00:01.678 A 2020/12/05 16:00:02.194 B
4.1 STEP1:テキストファイルのGrep
テキストを相手にするときはSelect-Stringコマンドレットを使う。
今日(2020/12/05)の部分だけをGrep抽出してみる。
PS > Select-String -Path "C:\temp\hoge.log" -Pattern "2020/12/05" C:\temp\hoge.log:5:2020/12/05 16:00:00.123 START C:\temp\hoge.log:6:2020/12/05 16:00:01.678 A C:\temp\hoge.log:7:2020/12/05 16:00:02.194 B
日付部分がハードコーディングで汎用性がないので、少し改編。Get-Dateコマンドレットで今日の日付を取得しyyyy/MM/dd形式でGrepする。
PS > Select-String -Path "C:\temp\hoge.log" -Pattern ("{0:yyyy/MM/dd}" -f (Get-Date)) C:\temp\hoge.log:5:2020/12/05 16:00:00.123 START C:\temp\hoge.log:6:2020/12/05 16:00:01.678 A C:\temp\hoge.log:7:2020/12/05 16:00:02.194 B
4.2 STEP2:条件1=今日のログ、条件2=特定文字列として「条件1かつ条件2」でGrepするには・・・
始めに考えたのは、Select-Stringを2回実施。例えば、今日のログ and "START"を含む行を表示させてみる。よくやるパターンだ。
PS > Select-String -Path "C:\temp\hoge.log" -Pattern ("{0:yyyy/MM/dd}" -f (Get-Date)) | Select-String -Pattern "START" C:\temp\hoge.log:5:2020/12/05 16:00:00.123 START
別解として、-Patternで正規表現を使ってみたやり方。
PS > Select-String -Path "C:\temp\hoge.log" -Pattern ("{0:yyyy/MM/dd.*START}" -f (Get-Date)) C:\temp\hoge.log:5:2020/12/05 16:00:00.123 START
どっちでもいいけど、-fのフォーマット指定に文字列を入れるのを良しとしないなら、以下のようにも書ける。
PS > Select-String -Path "C:\temp\hoge.log" -Pattern (("{0:yyyy/MM/dd}" -f (Get-Date)) + ".*START") C:\temp\hoge.log:5:2020/12/05 16:00:00.123 START
4.3 STEP3:今日のログで特定文字列を含む行はあるのか、ないのか?
STEP2までで、凡そ自分が欲しい情報だけを取得する方法が分かった。では、「自分が欲しい情報があったのか?」をプログラム的に判断してみたい。
これができれば、「今日の終了ログがあるか?なければメールして!」みたいな簡易的な異常検知スクリプトが実現できる。
さて「あるか、ないか」を判断するには、Select-Stringが返している情報が0なのか、そうでないのかを見ればいい。
PS > (Select-String -Path "C:\temp\hoge.log" -Pattern ("{0:yyyy/MM/dd.*END}" -f (Get-Date))).count 0 PS > (Select-String -Path "C:\temp\hoge.log" -Pattern ("{0:yyyy/MM/dd.*START}" -f (Get-Date))).count 1
結果は変数に格納できる。
PS > $a = (Select-String -Path "C:\temp\hoge.log" -Pattern ("{0:yyyy/MM/dd.*START}" -f (Get-Date))).count PS > $a 1
あとは、この変数の中身をifなどで判断する(古い手法だ)。
PS > $a = (Select-String -Path "C:\temp\hoge.log" -Pattern ("{0:yyyy/MM/dd.*START}" -f (Get-Date))).count PS > $a 1 PS > if($a -ne 0){echo "exist"} exist
今回のログファイルでは2020/12/05のENDログがないので、それをチェックしてメールする。
PS > $a = (Select-String -Path "C:\temp\hoge.log" -Pattern ("{0:yyyy/MM/dd.*END}" -f (Get-Date))).count PS > $a 0 PS > if($a -eq 0){Send-MailMessage xxxxxxxx} ※Send-MailMessageについては省略
※注意:厳密な”END”判定ではない。例えば”ENDOMAME"(エンドウマメ)という文字列も”END”を含んでいるので検出してしまう。この点は今は議論しない。
終.獲得した知識
<関連記事> PowerShell grepみたいなコマンドレット3つ