面倒な手作業をシェルスクリプトに任せる

# はじめに

[CYBIRD Advent Calendar 2022](https://qiita.com/advent-calendar/2022/cybird) の14日目担当の@cy-naullと申します。2021年新卒入社、2年目のサーバサイドエンジニアです。
13日目は、@dave_cさんの「[Laravel Actionsのご紹介](https://qiita.com/dave_c/private/72411a53466f51ed567b)」で、日本語にわかりやすく翻訳されており、内容もとても興味深いものでした！

# 概要

業務などで、「これ手作業でできるけど、めんどくさくない...？」という経験があるのではないかと思います。1回くらいなら手作業で済ませた方が早いこともありますが、定常的に発生するものですと、手間もかかりミスも起こり得ることもあります...。
今回はそういった作業を、sedなどを使用したシェルスクリプトで手間を減らそう！という記事となっております。なお、今回の作業環境はmacOSとなります。

# 目次
[1. 手作業で行っていたものについて](#1-手作業で行っていたものについて)
[2. シェルスクリプトで実行できるようにする](#2-シェルスクリプトで実行できるようにする)
[3. まとめ](#2-シェルスクリプトで実行できるようにする)


# 1. 手作業で行っていたものについて

簡易的にまとめると、月の初めに2つのサーバにある先月のログを1つにまとめ、特定のワードについて取り出し、データを整形する、といった作業になります。これらの作業を以下に分割し、シェルスクリプトで実行できるようにしていこうと思います。

* 2つのサーバにある先月のログを1つにまとめる
* 特定のワードについて取り出す
* データを整形する


# 2. シェルスクリプトで実行できるようにする

###  2つのサーバにある先月のログを1つにまとめる

まずは、サーバ上にある複数のログをローカルにSCPで持ってきて、1つにまとめます。今回、2つのサーバにあるファイル名が同じなので上書き防止のためSCPした後にリネームを行っています。

一括で複数ファイルをリネームする方法は以下のサイトを参考にさせていただいております。

https://engineeringnote.hateblo.jp/entry/unix_linux/command/rename_all_file

```shell:hoge.sh
#!/bin/zsh

# 先月のログのみ取得したいので、フォーマットを整え変数化する
LASTMONTH=`date -v -1m +'%Y%m'`

# ローカル上に新規フォルダを作成、移動
mkdir ~/hoge/${LASTMONTH}
cd ~/hoge/${LASTMONTH}

# scpマンドで先月のフォルダを指定し、対象のファイルを先ほど作成したフォルダに格納
scp -i key user@***.***.***.**1:~/logs/${LASTMONTH}/server.log.\*.gz ~/hoge/${LASTMONTH}/
# 取得したファイル群に、1つ目のサーバからのものと分かるようmvでリネーム
# ※sedで、"/"を使用すると階層を表す「/」と混ざりうまくいかないので今回は"|"を使用
ls *.gz | sed -e 's|.gz||g' | xargs -IX mv X.gz X_web1.gz

# 2つ目のサーバからも同様に取得
scp -i key user@***.***.***.**2:~/logs/${LASTMONTH}/server.log.\*.gz ~/hoge/${LASTMONTH}/
# grep -v で1つ目のサーバから取得したものを除外し、リネームする
ls *.gz | grep -v _web1 | sed -e 's|.gz||g' | xargs -IX mv X.gz X_web2.gz
```
#### 実行後①

対象のファイルが取得でき、それぞれのファイル名の末尾に、どのサーバから取得したものかの情報がリネームにより追加されています。

```
$ cd ~/hoge/202211
$ ls
server.log.20221101_web1.gz
server.log.20221101_web2.gz
server.log.20221102_web1.gz
server.log.20221102_web2.gz
...
```

<br>

###  特定のワードについて取り出す

続いて、取得したログについて特定のワードで抽出し、テキストファイルに書き込んでいきます。

```shell:hoge.sh
# ">>"を使用することで、追記書き込みになる
zgrep 'hoge' ~/hoge/${LASTMONTH}/server.log.${LASTMONTH}* >> ~/hoge/${LASTMONTH}/${LASTMONTH}.txt
zgrep 'fuga' ~/hoge/${LASTMONTH}/server.log.${LASTMONTH}* >> ~/hoge/${LASTMONTH}/${LASTMONTH}.txt

（取得したいワード分繰り返す）
```

#### 実行後②

ログの中にある特定のワードについて、行単位で取得できています。

```
$ less 202211.txt
~/hoge/202211/server.log.20221101_web1.gz:1667228400,"hoge","aaa","111" ...
~/hoge/202211/server.log.20221101_web2.gz:1667228400,"hoge","bbb","222" ...
~/hoge/202211/server.log.20221102_web1.gz:1667314800,"fuga","ccc","333" ...
~/hoge/202211/server.log.20221102_web2.gz:1667314800,"fuga","ddd","444" ...
...
```

<br>

### データを整形する

最後に、抽出したデータを整形していきます。今回整えたい内容としては、下記となります。
* データの中に不要なテキスト(抽出したフォルダ名)があるためそれらを削除
* データにUNIXTIMEがあり、これらをシステム標準時に変換

```shell:hoge.sh
# ログに抽出したフォルダ名が記載されているため、sedで削除
sed -i -e 's|.*gz:||g' ~/hoge/${LASTMONTH}/${LASTMONTH}.txt

# UNIXTIMEをcutで決め打ちで取得
export UNIXTIME=`eval cut -b 1-10 ${LASTMONTH}.txt`
# for文で1つずつ、dateでフォーマットした日付に変換し、sedで置換する
for time in ${UNIXTIME[@]}; do
  export NEWTIME=`eval echo "$(date -r $time +'%Y/%m/%d %H:%M:%S')"`
  sed -i -e "s|$time|$NEWTIME|g" ./${LASTMONTH}.txt

done
```

#### 実行後③
整形前にあった不要なテキストが削除され、UNIXTIMEも標準時間に変換されています。

```
$ less 202211.txt
2022/11/01 00:00:00,"hoge","aaa","111" ...
2022/11/01 00:00:00,"hoge","bbb","222" ...
2022/11/02 00:00:00,"fuga","ccc","333" ...
2022/11/02 00:00:00,"fuga","ddd","444" ...
...
```

<br>

# 3. まとめ
今回シェルスクリプトを作成してみて、便利なコマンドが沢山あるのだと勉強になりました！
手作業でできるけど、コード書くのも大変かなと思っておりましたが、毎月手作業で行っていたものがなくなりハッピーです。

次回、[CYBIRD Advent Calendar 2022](https://qiita.com/advent-calendar/2022/cybird) の15日目は、@kanachaさんの「unity1week「そろえる」の参加記録」です。お楽しみに！