[Bash]特定月のログファイルを圧縮する

特定月のログファイルを圧縮するシェルスクリプトのサンプルコード（覚え書き）。
デフォルトは前月（コマンドライン引数なし）で、コマンドライン引数（第1引数）に年月を指定すると、その年月分のログファイルを圧縮できる、という内容になっています。

## 環境
* OS: Amazon Linux2

## 概要

概要は以下の通りで、2パターンの処理が可能。

#### 1.コマンドライン引数がない場合
①対象月の圧縮ファイルの有無を確認
②backupディレクトリ配下を削除
③前月に作成されたログファイルを圧縮

#### 2.コマンドライン引数（第1引数）がある場合
①コマンドライン引数（第1引数の指定の仕方が正しいか（yyyymmとなっているか）確認
②対象月の圧縮ファイルの有無を確認
③コマンドライン引数（第1引数）に作成された年月のログファイルを圧縮

#### ※ 途中でエラーが発生した場合
①指定したメールアドレスにエラーメールを送信
→ コード内では、from ,to とも、hoge@example.comとしていますが、適宜変更を。

#### 注意点
* ファイルのタイムスタンプではなく、ファイル名で対象を見分けています。

## 前提条件

後続のコードで登場する、ディレクトリ情報は以下の通り。

|ディレクトリ名 |用途 |
|---|---|
|/product/aaa|圧縮対象となるファイルが格納されている|
|/product/compress/aaa |圧縮した（圧縮後の）ファイルを格納  |
|/product/aaa/backup |圧縮した（圧縮後の）ファイルのバックアップ（圧縮しない状態）を格納 |


## コード

```bash:compress_log.sh
#!/bin/bash

function compress(){
  # 対象ディレクトリに移動
  TARGET_DIR="/product/aaa"
  cd $TARGET_DIR

  # 処理対象月のデフォルト：前月
  THIS_MONTH=`date +'%Y%m01'`
  TARGET_MONTH=`date -d "${THIS_MONTH} 1 month ago" +'%Y%m'`
  # 圧縮ファイル格納ディレクトリ
  COMPRESS_DIR="/product/compress/aaa"
  # バックアップ用ディレクトリ
  BACKUP_DIR="/product/aaa/backup"

  if [ $# != 0 ]; then
    # 第1引数ありの場合、対象月を上書き
    if [[ !($1 =~ [0-9]{6}) ]]; then
      echo "第1引数の形式は、yyyymmです"
      exit
    fi
    export TARGET_MONTH=$1
  fi

  # 対象月の圧縮ファイルが存在する場合は処理を終了
  COMPRESS_FORMAT="dailylog_${TARGET_MONTH}.zip"
  if ls $COMPRESS_DIR/$COMPRESS_FORMAT > /dev/null 2>&1
  then
    echo "処理済です"
    compress_error
    exit
  fi

  if [ $# = 0 ]; then
    # 第1引数指定のない場合（通常の月毎の処理）にbackup配下を削除
    echo "backupディレクトリ配下のファイルを削除します"
    rm -frv $BACKUP_DIR/*
    echo "backupディレクトリ配下のファイル削除が完了しました"
  fi

  # ログファイルの圧縮
  FILES="dailylog_${TARGET_MONTH}*.log"
  if ls $FILES > /dev/null 2>&1
  then
    echo "${TARGET_MONTH:0:4}年${TARGET_MONTH:4:2}月分の日次ログファイルを圧縮します"
    zip -r $COMPRESS_DIR/$COMPRESS_FORMAT $FILES
    mv $FILES $BACKUP_DIR/
    echo "${TARGET_MONTH:0:4}年${TARGET_MONTH:4:2}月分の日次ログファイルの圧縮が完了しました"
  else
    echo "${TARGET_MONTH:0:4}年${TARGET_MONTH:4:2}月分の日次ログファイルは存在しません"
  fi

}

function compress_error() {
  # エラー処理
  HOSTNAME=$(hostname)
  echo "日次ログファイル圧縮処理に失敗しました"
  echo -e "日次ログファイル圧縮処理に失敗しました" | mail -s "【サービス名】日次ログファイル圧縮処理失敗@${HOSTNAME}" -r hoge@example.com hoge@example.com
}

echo "======= 処理開始=======" && (compress $1 || compress_error) && echo "======= 処理終了======="
```

上のプログラムでは、zip形式を用いていますが、必要に応じて圧縮フォーマット（COMPRESS_FORMAT）および圧縮形式（zip -rで始まる箇所）を変更してください。
[圧縮展開系のコマンドのまとめ | Qiita](https://qiita.com/wnoguchi/items/cb0fa7c11b119e96f1e5)
辺りが、参考になるかと。

以下圧縮形式としてメジャーなgzip, bz2, xzを用いる場合。

```bash
# gzip
COMPRESS_FORMAT="dailylog_${TARGET_MONTH}.tar.gz"
tar cvzf $COMPRESS_DIR/$COMPRESS_FORMAT $FILES
# bz2形式
COMPRESS_FORMAT="dailylog_${TARGET_MONTH}.tar.bz2"
tar cvjf $COMPRESS_DIR/$COMPRESS_FORMAT $FILES
# xz形式
COMPRESS_FORMAT="dailylog_${TARGET_MONTH}.tar.xz"
tar cvJf $COMPRESS_DIR/$COMPRESS_FORMAT $FILES
```

## クーロン登録

毎月2日の15:00に処理を実行＆プログラムと同階層のログディレクトリ配下にログ出力する場合は以下の通り。

```
# compress daily log
00 15 02 * * /usr/local/src/shell/compress_log/compress_log.sh >> /usr/local/src/shell/compress_log/log/compress_log_`date +\%Y\%m\%d`.log 2>&1
```

## 参考

* [dateコマンドで前月を計算する時の注意(前月に基準日の日付がない場合) | カタカタブログ](https://totech.hateblo.jp/entry/2015/07/31/063037)
* [シェル変数($#)で引数チェックをする | ITを使っていこう](https://it-ojisan.tokyo/sh-arg-check/)
* [シェルスクリプトで正規表現マッチ | Yura YuLife](https://yura2.hateblo.jp/entry/2015/12/17/%E3%82%B7%E3%82%A7%E3%83%AB%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%81%A7%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE%E3%83%9E%E3%83%83%E3%83%81)
* [環境変数、シェル変数の動きメモ | Qiita](https://qiita.com/nikofu501/items/7c46ab549f60a6937182)
* [よくあるシェルスクリプトの小技【if 編】 | hosiiのメモ帳](https://hosii.net/?p=369)
* [if 文と test コマンド | UNIX & LINUXコマンド・シェルスクリプト リファレンス](https://shellscript.sunone.me/if_and_test.html)
* [bashで変数から部分文字列を取得する | Qiita](https://qiita.com/koara-local/items/04d3efd1031ea62d8db5)