亀の甲羅2

今日もまた朝とく起きて励まなん窓に明るきありあけの月

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”を含んでいるので検出してしまう。この点は今は議論しない。

終.獲得した知識

  • テキストファイル(とくにログファイル)をGrepして、欲しい情報を得る方法
  • Grepした結果があるのか、ないのかを判別する方法

<関連記事> PowerShell grepみたいなコマンドレット3つ