ファイルの自動バックアップシェルスクリプト

# バックアップスクリプトの仕様
- 1日に1回、cronでスクリプトを起動しバックアップする
- `/home/user/data/` の中にあるディレクトリごとにZIPファイルにバックアップする。
- バックアップファイルの置き場所は `/bar/backup/対象ディレクトリ名/` とする
- スクリプト実行時に、バックアップから `2週間分の秒数＋マージン30秒` を経過している場合は自動削除する
- ただし、バックアップファイル名に保管接尾辞 `_preserved` がついている場合は自動削除しない
- スクリプト起動日が月末日であれば、バックアップファイル名に保管接尾辞をつける

# バックアップファイル名の仕様
下記のいずれかになる。
- `対象ディレクトリ名_YYYYMMDD-HHMM-S.zip`
- `対象ディレクトリ名_YYYYMMDD-HHMM-S_preserved.zip`

※ `S` はエポック秒

# 使用上の注意
お使いの環境で `zip` コマンドが利用可能である必要があります。
`dnf install zip` (RedHat系)、`apt install zip` (Debian系)等でパッケージをインストールするなどしてください。
`/var/backup/` に適切なパーミッションを設定してください。

# 実際のシェルスクリプト

```shell:backup.sh
#!/bin/bash

# ============================================================ #
#  Copyright (c) 2023 CIB-MC
#  Released under the MIT license
#  https://opensource.org/licenses/mit-license.php
# ============================================================ #

backup_from="/home/user/data/"
backup_dest="/var/backup/"
preserved_suffix="_preserved"
sec_to_live=$((60 * 60 * 24 * 7 * 2 + 30)) # 60sec x 60min x 24hour x 7day x 2week + 30sec

exit_status=0
next_day=`date -d '+1 day' +%d`
str_ts=`date +%Y%m%d-%H%M_%s`
epoch_now=`date +%s`
file_name_suffix=""


# ============================================================ #
#  set backup file to preserved if today is last day of month
# ============================================================ #

if [ $next_day -eq 1 ]; then
        file_name_suffix=$preserved_suffix
fi


# ============================================================ #
#  backup dirs in backup_from
# ============================================================ #

find_cond="${backup_from}*"
dirs_from=`find $find_cond -maxdepth 0 -type d`

for dir_from_path in $dirs_from;
do
        [[ $dir_from_path =~ /([^/]+)$ ]]
        dir_from_name=${BASH_REMATCH[1]}
        dir_dest="${backup_dest}${dir_from_name}/"
        if [ ! -d $dir_dest ]; then
                mkdir $dir_dest
                if [ $? -ne 0 ]; then
                        exit_status=1
                fi
        fi
        file_name="${dir_from_name}_${str_ts}${file_name_suffix}.zip"
        file_path=$dir_dest$file_name
        backup_command="cd ${backup_from}; zip -q -r ${file_path} ${dir_from_name};"
        eval $backup_command
        if [ $? -ne 0 ]; then
                exit_status=1
        fi
done


# ============================================================ #
#  delete backup files over sec to live and are not preserved
# ============================================================ #

find_backup_file_cond="${backup_dest}*"
files_backup=`find $find_backup_file_cond -type f -name "*.zip"`
for file_backup in $files_backup;
do
        if [[ !($file_backup =~ ${preserved_suffix}\.zip$ ) && ($file_backup =~ _([0-9]+)\.zip$) ]]; then
                epoch_backup=${BASH_REMATCH[1]}
                if [ $(($epoch_now - $epoch_backup)) -gt $sec_to_live ]; then
                        delete_command="rm -f ${file_backup};"
                        eval $delete_command
                        if [ $? -ne 0 ]; then
                                exit_status=1
                        fi
                fi
        fi
done


# ============================================================ #

if [ $exit_status -ne 0 ]; then
        echo "=== BACKUP PROCESS WAS NOT ALL SUCCEEDED! ==="
        echo "Please read logs above and take action you need to do."
fi
exit $exit_status
```

# その他
バックアップファイルが `tar.gz` でないと困る場合など、改造はライセンスを守ってご自由にどうぞ。