grepコマンドでログから欲しい情報だけを効率的に取得する

# はじめに
大量のログが吐かれたファイルの中から欲しいデータだけを取り出したい場合は、`grep`コマンドが活用できます。
本記事では`grep`コマンドを使用しサンプルで作成したログファイルから、対象のデータを取り出す方法を10パターンほど記載いたします。

# 本記事のゴール
- grepコマンドの使い方がなんとなくわかる
- 10パターンくらいgrepコマンドの活用例を把握できる

# 環境
Git Bash：2.46.0
Python 3.12.4


# grepで引っ掛ける対象のデータを作成

gerp検索で引っ掛けるための下記のようなサンプルログを作成します。

```:sample_log.txt
～～～
2024-08-13 11:51:17 | フルーツ: オレンジ | 食べ物: 寿司 | 数量: 4 | 価格: 4380.75円 | ID: 7091
2024-08-10 22:33:17 | フルーツ: オレンジ | 食べ物: サラダ | 数量: 3 | 価格: 3170.49円 | ID: 1833
2024-08-21 06:45:17 | フルーツ: パイナップル | 食べ物: パスタ | 数量: 7 | 価格: 1476.84円 | ID: 1049
2024-08-13 16:15:17 | フルーツ: パイナップル | 食べ物: ピザ | 数量: 5 | 価格: 1768.78円 | ID: 9719
2024-08-05 04:07:17 | フルーツ: メロン | 食べ物: ピザ | 数量: 6 | 価格: 2881.62円 | ID: 1218
～～～
```

今回、サンプルログの作成には次のソースを使います。
本記事では下記のソースで作成したログファイルを後で使用していきます。

```python:generate_sample_log.py
import random
from datetime import datetime, timedelta

fruits = ["リンゴ", "バナナ", "オレンジ", "ぶどう", "メロン", "いちご", "パイナップル"]
foods = ["ラーメン", "カレー", "ハンバーガー", "ピザ", "寿司", "パスタ", "サラダ"]

# サンプルデータの生成
def generate_log_entry():
    timestamp = (datetime.now() - timedelta(
        days=random.randint(0, 30),
        hours=random.randint(0, 23),
        minutes=random.randint(0, 59)
    )).strftime("%Y-%m-%d %H:%M:%S")
    fruit = random.choice(fruits)
    food = random.choice(foods)
    quantity = random.randint(1, 10)
    price = round(random.uniform(100, 5000), 2)
    random_number = random.randint(1000, 9999)
    
    return f"{timestamp} | フルーツ: {fruit} | 食べ物: {food} | 数量: {quantity} | 価格: {price}円 | ID: {random_number}"

# ログを100件書き込み
with open('sample_log.txt', 'w', encoding='utf-8') as f:
    for _ in range(100):
        f.write(generate_log_entry() + '\n')

print("サンプルログファイル 'sample_log.txt' が生成されました。")
```

次のコマンドでスクリプトを実行し、`sample_log.txt`を作成します。

```bash
python generate_sample_log.py 
```

ログファイルが作成されたらデータの準備はできたので、実際に`grep`コマンドを試していきます。

:::note info

##### ファイルの最初の5行を表示

ログファイルの内容を少し見たい時には、`head`コマンドを使用すると最初の数行を確認できます。
次のコマンドでは最初の5行をログに出しています。

```
head -n 5 sample_log.txt
```

```:実行結果
$ head -n 5 sample_log.txt
2024-08-19 17:37:25 | フルーツ: メロン | 食べ物: パスタ | 数量: 2 | 価格: 4438.27円 | ID: 5716
2024-08-10 06:43:25 | フルーツ: リンゴ | 食べ物: サラダ | 数量: 9 | 価格: 3364.11円 | ID: 1802
2024-08-17 19:37:25 | フルーツ: メロン | 食べ物: ハンバーガー | 数量: 9 | 価格: 291.61円 | ID: 4392
2024-08-16 11:07:25 | フルーツ: メロン | 食べ物: ラーメン | 数量: 6 | 価格: 4603.28円 | ID: 9688
2024-08-24 13:29:25 | フルーツ: リンゴ | 食べ物: ラーメン | 数量: 5 | 価格: 1165.92円 | ID: 8223
```

:::



# 1. 基本的な文字列マッチング

特定の文字にパターンマッチングした行を抽出します。

```
grep "検索対象の文字" 検索対象のファイル
```

次のコマンドで `リンゴ` を含むすべての行を表示します。

```:実行結果
$ grep "リンゴ" sample_log.txt
2024-08-10 06:43:25 | フルーツ: リンゴ | 食べ物: サラダ | 数量: 9 | 価格: 3364.11円 | ID: 1802
2024-08-24 13:29:25 | フルーツ: リンゴ | 食べ物: ラーメン | 数量: 5 | 価格: 1165.92円 | ID: 8223
2024-08-17 14:51:25 | フルーツ: リンゴ | 食べ物: 寿司 | 数量: 7 | 価格: 1375.62円 | ID: 2600
2024-08-01 17:17:25 | フルーツ: リンゴ | 食べ物: パスタ | 数量: 5 | 価格: 4155.64円 | ID: 4238
～～～
```

# 2. 複数パターンの文字列マッチング

複数の文字にパターンマッチングした行を抽出します。

```
grep -E "検索対象の文字1|検索対象の文字2|検索対象の文字3" 検索対象のファイル
```

次のコマンドで `リンゴ` or `バナナ` or `パイナップル`を含むすべての行を表示します。

```:実行結果
$ grep -E "リンゴ|バナナ|パイナップル" sample_log.txt
2024-08-10 06:43:25 | フルーツ: リンゴ | 食べ物: サラダ | 数量: 9 | 価格: 3364.11円 | ID: 1802
2024-08-24 13:29:25 | フルーツ: リンゴ | 食べ物: ラーメン | 数量: 5 | 価格: 1165.92円 | ID: 8223
2024-08-03 14:09:25 | フルーツ: パイナップル | 食べ物: カレー | 数量: 6 | 価格: 623.68円 | ID: 9457
2024-08-22 16:54:25 | フルーツ: バナナ | 食べ物: ハンバーガー | 数量: 7 | 価格: 781.66円 | ID: 3601
～～～
```

# 3. 特定のパターンに対するマッチング

特定のパターンマッチングした行を抽出します。

```
grep "価格: 1.*" 検索対象のファイル
```

次のコマンドで「価格：1」で始まり、その後に任意の文字列が続く行を表示します。

```:実行結果
$ grep "価格: 1.*" sample_log.txt
2024-08-24 13:29:25 | フルーツ: リンゴ | 食べ物: ラーメン | 数量: 5 | 価格: 1165.92円 | ID: 8223
2024-08-25 21:39:25 | フルーツ: メロン | 食べ物: ラーメン | 数量: 9 | 価格: 1855.55円 | ID: 8772
2024-08-17 14:51:25 | フルーツ: リンゴ | 食べ物: 寿司 | 数量: 7 | 価格: 1375.62円 | ID: 2600
2024-08-24 00:33:25 | フルーツ: オレンジ | 食べ物: ピザ | 数量: 3 | 価格: 103.62円 | ID: 4715
～～～
```

# 4. 行頭のパターンマッチング

行頭の文字に対してパターンマッチングした行を抽出します。

```
grep "^先頭の文字" 検索対象のファイル
```

次のコマンドでは行頭に`2024-`がついている行を抽出しています。
（`sample_log.txt`では全ての行頭に`2024-`がついているため全件抽出と同じ事になります。）

```:実行結果
$ grep "^2024-" sample_log.txt
2024-08-19 17:37:25 | フルーツ: メロン | 食べ物: パスタ | 数量: 2 | 価格: 4438.27円 | ID: 5716
2024-08-10 06:43:25 | フルーツ: リンゴ | 食べ物: サラダ | 数量: 9 | 価格: 3364.11円 | ID: 1802
2024-08-17 19:37:25 | フルーツ: メロン | 食べ物: ハンバーガー | 数量: 9 | 価格: 291.61円 | ID: 4392
2024-08-16 11:07:25 | フルーツ: メロン | 食べ物: ラーメン | 数量: 6 | 価格: 4603.28円 | ID: 9688
2024-08-24 13:29:25 | フルーツ: リンゴ | 食べ物: ラーメン | 数量: 5 | 価格: 1165.92円 | ID: 8223
～～～
```

# 5. 行末のパターンマッチング

行末の文字に対してパターンマッチングした行を抽出します。

```
grep "末尾の文字$" 検索対象のファイル
```

次のコマンドでは行末が`5000`の文字の行を抽出します。

```:実行結果
$ grep "5000$" sample_log.txt
2024-08-20 22:36:25 | フルーツ: パイナップル | 食べ物: ハンバーガー | 数量: 6 | 価格: 2121.39円 | ID: 5000
```

# 6.パターンマッチした前後の行を表示する

パターンマッチした行の前後1行を抽出します。

```
grep -C 行数 "検索文字列" 検索対象のファイル
```

次のコマンドでは `5000` の文字がある行の前後１行を抽出します。

```:実行結果
$ grep -C 1 "5000" sample_log.txt
2024-08-07 04:37:25 | フルーツ: いちご | 食べ物: ハンバーガー | 数量: 6 | 価格: 3819.43円 | ID: 5581
2024-08-20 22:36:25 | フルーツ: パイナップル | 食べ物: ハンバーガー | 数量: 6 | 価格: 2121.39円 | ID: 5000        
2024-08-13 04:35:25 | フルーツ: リンゴ | 食べ物: カレー | 数量: 2 | 価格: 4403.51円 | ID: 2645
```

# 7．パターンマッチしない行を表示する

特定の文字列を含まない行のみを表示します。

```
grep -v "特定の文字列" 検索対象のファイル
```

次のコマンドでは `リンゴ` の文字列が含まれない行を表示します。

```:実行結果
$ grep -v "リンゴ" sample_log.txt
2024-08-19 17:37:25 | フルーツ: メロン | 食べ物: パスタ | 数量: 2 | 価格: 4438.27円 | ID: 5716
2024-08-17 19:37:25 | フルーツ: メロン | 食べ物: ハンバーガー | 数量: 9 | 価格: 291.61円 | ID: 4392
2024-08-16 11:07:25 | フルーツ: メロン | 食べ物: ラーメン | 数量: 6 | 価格: 4603.28円 | ID: 9688
2024-08-10 18:24:25 | フルーツ: いちご | 食べ物: ピザ | 数量: 1 | 価格: 4265.71円 | ID: 1839
```


# 8.パターンマッチした行とその行番号を表示する

パターンにマッチした対象の行とその行番号も表示します。

```
grep -n "検索文字列" 検索対象のファイル
```

次のコマンドでは `リンゴ` の文字列にマッチした行とその行番号を表示します。

```:実行結果
$ grep -n "リンゴ" sample_log.txt
2:2024-08-10 06:43:25 | フルーツ: リンゴ | 食べ物: サラダ | 数量: 9 | 価格: 3364.11円 | ID: 1802
5:2024-08-24 13:29:25 | フルーツ: リンゴ | 食べ物: ラーメン | 数量: 5 | 価格: 1165.92円 | ID: 8223
14:2024-08-17 14:51:25 | フルーツ: リンゴ | 食べ物: 寿司 | 数量: 7 | 価格: 1375.62円 | ID: 2600
16:2024-08-01 17:17:25 | フルーツ: リンゴ | 食べ物: パスタ | 数量: 5 | 価格: 4155.64円 | ID: 4238
```

# 9 . パターンマッチした行を別ファイルに抽出する

パターンマッチした行だけを別ファイルに書き出します。

```
grep "検索対象の文字列" 元のログファイル > 抽出先のログファイル
```

元のログファイルを変更せずに、必要な情報だけを別ファイルに保存します。
次のコマンドは `リンゴ` の文字が含まれる行だけ、`extractred_apple_log.txt` ファイルに書き出します。

```:実行コマンド
$ grep "リンゴ" sample_log.txt > extractred_apple_log.txt
```

```:extractred_apple_log.txt
2024-08-10 06:43:25 | フルーツ: リンゴ | 食べ物: サラダ | 数量: 9 | 価格: 3364.11円 | ID: 1802
2024-08-24 13:29:25 | フルーツ: リンゴ | 食べ物: ラーメン | 数量: 5 | 価格: 1165.92円 | ID: 8223
2024-08-17 14:51:25 | フルーツ: リンゴ | 食べ物: 寿司 | 数量: 7 | 価格: 1375.62円 | ID: 2600
2024-08-01 17:17:25 | フルーツ: リンゴ | 食べ物: パスタ | 数量: 5 | 価格: 4155.64円 | ID: 4238
```

# 10 .パターンマッチした行の総数をカウント

パターンにマッチした行の総数のみ表示します。

```
grep -c "検索文字列" 検索対象のファイル
```

次のコマンドでは `リンゴ` の文字列が含まれる行の総数をカウントします。

```:実行結果
$ grep -c "リンゴ" sample_log.txt
14
```

# 終わりに
最近 `grep` コマンドを使ってみてすごい便利だったので、もう少し使い方をキャッチアップしようと思い、本記事では10個のgrepコマンドとその実行結果を紹介しました。
まだまだいくつも活用パターンはあると思いますので、`grep` が活用できそうなタイミングが来たらその都度キャッチアップしていきます。