PostgreSQLデータベースのダンプ作成方法（シェルスクリプト & Docker）

# はじめに
まず以下のコードをご覧ください。

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

echo "start dump"

DST_FILE=${DST_DIR}/$(date +%Y%m%d_%H%M).sql

if [ ! -d $DST_DIR ]; then
  mkdir -p $DST_DIR
fi

docker run --rm -it -w="/work" -v $(pwd):/work --env PGPASSWORD=${APP_POSTGRES_PASS} postgres:15.4-alpine bash -c "\
pg_dump --schema=public \
-T job_postings \
-T companies \
-h ${APP_POSTGRES_HOST} -p ${APP_POSTGRES_PORT} -U ${APP_POSTGRES_USER} -d my_dump_db > ${DST_FILE}"

echo "finish dump"

echo "start dump sort"

$(dirname "$0")/pg_dump_sort $DST_FILE > $(echo "$DST_FILE" | sed 's/\.sql$//')_sorted.sql

echo "finish dump sort"
```

どんな処理を行なっているのかイメージがつきますか？
このシェルスクリプトは、**PostgreSQLデータベースのダンプを作成し、特定のテーブルを除外してファイルに保存するためのもの**です。初心者向けに、スクリプトの各部分について詳しく説明します。

# スクリプトの解説
### 1. 　ダンプ処理の開始
```bash:dump.sh
echo "start dump"
```
この行では、ダンプ処理の開始を示すメッセージを出力しています。

### 2.　ダンプファイルの名前生成
```bash:dump.sh
DST_FILE=${DST_DIR}/$(date +%Y%m%d_%H%M).sql
```
ここでは、ダンプファイルの名前を生成しています。現在の日時を使用してファイル名を作成し、```DST_DIR```変数で指定されたディレクトリに保存します。例えば、2023年5月20日 10時30分にスクリプトを実行した場合、ファイル名は20230520_1030.sqlになります。

### 3. 　ダンプファイル保存ディレクトリの作成
```bash:dump.sh
if [ ! -d $DST_DIR ]; then
    mkdir -p $DST_DIR
fi
```

ダンプファイルを保存するディレクトリが存在しない場合、このコードブロックでディレクトリを作成します。```-d```オプションを使用して、```DST_DIR```変数で指定されたディレクトリが存在するかどうかを確認し、存在しない場合は```mkdir -p```コマンドでディレクトリを作成します。

### 4. 　Dockerコンテナを使用したPostgreSQLダンプの作成
```sh:bash
docker run --rm -it -w="/work" -v $(pwd):/work --env PGPASSWORD=${APP_POSTGRES_PASS} postgres:15.4-alpine bash -c "..."
```
このコマンドでは、Dockerコンテナを使用してPostgreSQLのダンプを作成します。各オプションの説明は以下の通りです。

```--rm```： コンテナ終了後に自動的にコンテナを削除します。
```-it```： インタラクティブモードでコンテナを実行します。
```-w="/work"```： コンテナ内の作業ディレクトリを```"/work"```に設定します。
```-v $(pwd):/work```： カレントディレクトリをコンテナ内の```"/work"```ディレクトリにマウントします。
```--env PGPASSWORD=${APP_POSTGRES_PASS}```： 環境変数```PGPASSWORD```を設定して、PostgreSQLの認証パスワードを指定します。
```postgres:15.4-alpine```： 使用するPostgreSQLのDockerイメージを指定します。
```bash -c "..."```： コンテナ内でbashシェルを実行し、指定したコマンドを実行します。

### 5. 　pg_dumpコマンドを使用したデータベースダンプの作成
```sh:dump.sh
pg_dump --schema=public \
  -T job_postings \
  -T companies \
  ...
  -h ${APP_POSTGRES_HOST} -p ${APP_POSTGRES_PORT} -U ${APP_POSTGRES_USER} -d my_dump_db > ${DST_FILE}
```
```pg_dump```コマンドを使用して、指定したテーブルを除外してデータベースのダンプを作成します。主なオプションは以下の通りです。

```--schema=public```： "public"スキーマのみをダンプします。
```-T job_postings -T companies ...```： 除外するテーブルを指定します。
```-h ${APP_POSTGRES_HOST} -p ${APP_POSTGRES_PORT} -U ${APP_POSTGRES_USER}```： PostgreSQLの接続情報を指定します。
```-d my_dump_db```： ダンプ対象のデータベース名を指定します。
```> ${DST_FILE}```： ダンプ出力をファイルに保存します。

### 6. 　ダンプ処理の終了
```bash.dump.sh
echo "finish dump"
```
ダンプ処理の終了を示すメッセージを出力します。

### 7. 　ダンプファイルのソート処理の開始
```sh:dump.sh
echo "start dump sort"
```
ダンプファイルのソート処理の開始を示すメッセージを出力します。

### 8. 　pg_dump_sortスクリプトを使用したダンプファイルのソート
```sh:dump.sh
$(dirname "$0")/pg_dump_sort $DST_FILE > $(echo "$DST_FILE" | sed 's/\.sql$//')_sorted.sql
```

```pg_dump_sort```スクリプトを使用してダンプファイルをソートし、新しいファイルに保存します。```sed```コマンドを使用して、元のファイル名から```.sql```拡張子を削除し、```_sorted.sql```を追加して新しいファイル名を作成します。

### 9.　ダンプファイルのソート処理の終了
```sh:dump.sh
echo "finish dump sort"
```
ダンプファイルのソート処理の終了を示すメッセージを出力します。

# まとめ
このシェルスクリプトを実行することで、PostgreSQLデータベースから特定のテーブルを除外してダンプを作成し、ダンプファイルをソートして新しいファイルに保存することができます。Dockerコンテナを使用してPostgreSQLの環境を簡単に構築し、```pg_dump```コマンドでダンプを作成することができます。また、```pg_dump_sort```スクリプトを使用してダンプファイルをソートすることで、読みやすく管理しやすいダンプファイルを作成できます。
データベースのバックアップや移行作業を効率的に行うことができるため、ぜひご活用ください。

# ※ 補足
```#!/bin/bash```は、シェルスクリプトの最初の行に記述される**シバン**（shebang）と呼ばれる特別な指示です。シバンは、そのスクリプトを実行するためにどのインタプリタを使用するかをシステムに指示します。

```#!/bin/bash```は、具体的には以下の意味を持ちます。

```#!```は、**シバンの開始を示す**特別な記号です。これによって、システムはこの行がシバンであることを認識します。
```/bin/bash```は、このスクリプトを実行するために使用する**インタプリタのパス**を指定しています。この場合、```/bin```ディレクトリにある```bash```シェルを使用することを示しています。

つまり、```#!/bin/bash```は、このスクリプトが```Bash```シェルスクリプトであり、```Bash```インタプリタを使用して実行されるべきであることをシステムに伝えています。
シバンは、スクリプトファイルに実行権限が付与されている場合に機能します。スクリプトを実行すると、システムはシバンを読み取り、指定されたインタプリタを使用してスクリプトを実行します。
他のシェルやインタプリタを使用する場合は、シバンを適切に変更する必要があります。例えば、```Zsh```シェルを使用する場合は```#!/bin/zsh```、```Python```スクリプトの場合は```#!/usr/bin/env python3```などのように指定します。
シバンを正しく指定することで、スクリプトをシームレスに実行できるようになり、スクリプトの可搬性と互換性が向上します。