(続)S3にアップロード

[FileMakerのオブジェクトをS3にアップロードする](https://qiita.com/mackey1966/items/c78f3d7383c598536b0a)のその後だが、アップロードに時間がかかるので（10,000件で4時間）速くなる方法がないかAIに聞いたらxargsを使うとコマンドを並列処理できるらしい。以下がそのコード。
```upload_objects_to_s3.sh
#!/bin/bash

# 言語環境をen_US.UTF-8に設定
export LC_ALL=en_US.UTF-8

# cronで実行に必要
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
export PATH

# ログファイルのパス
LOG_FILE="/Users/iwaninc/Documents/tmp/upload_script.log"

# 停止ファイルのパス
STOP_FILE="/Users/iwaninc/Documents/tmp/stop_upload_script"

# ロックファイルのパス
LOCK_FILE="/Users/iwaninc/Documents/tmp/upload_script.lock"

# ロックファイルのチェックと作成
if [ -e "$LOCK_FILE" ]; then
    echo "$(date) Another instance is already running. Exiting." >> "$LOG_FILE"
    exit 1
else
    touch "$LOCK_FILE"
fi

# 終了時にロックファイルを削除する関数
cleanup() {
    rm -f "$LOCK_FILE"
    echo "$(date) Script finished, lock file removed." >> "$LOG_FILE"
}

# スクリプト終了時にcleanup関数を呼び出す
trap cleanup EXIT

# グローバル変数で停止フラグを設定
stop_flag=0

# シグナルハンドラ
trap 'stop_flag=1; echo "$(date) Received stop signal. Stopping gracefully..." >> "$LOG_FILE"' SIGINT SIGTERM

# 停止ファイルをチェックする関数
check_stop_file() {
    if [ -f "$STOP_FILE" ]; then
        echo "$(date) Stop file detected. Stopping process..." >> "$LOG_FILE"
        stop_flag=1
        rm -f "$STOP_FILE"  # 停止ファイルを削除
    fi
}

echo "$(date) Start..." >> "$LOG_FILE"

# アップロード先のS3バケット名
S3_BUCKET="<バケット名>"

# ディレクトリとプレフィックスの配列
DIRECTORIES=("/Users/iwaninc/Documents/object" "/Users/iwaninc/Documents/object2" "/Users/iwaninc/Documents/object3")
PREFIXES=("<プレフィックス1>" "<プレフィックス2>" "<プレフィックス3>")

# 並列処理の数（同時にアップロードするファイルの数）
PARALLEL_JOBS=10

upload_and_delete() {
    local file="$1"
    local bucket="$2"
    local prefix="$3"
    local filename=$(basename "$file")

    # 停止フラグをチェック
    if [ $stop_flag -eq 1 ]; then
        echo "$(date) Stopping process for file: $file" >> "$LOG_FILE"
        return
    fi

    if aws s3 cp "$file" "s3://$bucket/$prefix/$filename" --quiet; then
        echo "$(date) Uploaded: $file" >> "$LOG_FILE"
        rm "$file"
        echo "$(date) Deleted local file: $file" >> "$LOG_FILE"
    else
        echo "$(date) Upload failed: $file" >> "$LOG_FILE"
    fi
}

export -f upload_and_delete
export stop_flag
export LOG_FILE

for i in "${!DIRECTORIES[@]}"; do
    # 停止フラグをチェック
    check_stop_file
    if [ $stop_flag -eq 1 ]; then
        echo "$(date) Stopping process before processing directory: ${DIRECTORIES[$i]}" >> "$LOG_FILE"
        break
    fi

    DIR="${DIRECTORIES[$i]}"
    PREFIX="${PREFIXES[$i]}"
    
    echo "$(date) Processing directory: $DIR" >> "$LOG_FILE"
    
    # 並列処理でファイルをアップロード
    find "$DIR" -type f -print0 | xargs -0 -P "$PARALLEL_JOBS" -I {} bash -c '
        if [ $stop_flag -eq 0 ]; then
            upload_and_delete "{}" "$0" "$1"
        fi
    ' "$S3_BUCKET" "$PREFIX"
    
    echo "$(date) Finished processing directory: $DIR" >> "$LOG_FILE"
done

echo "$(date) Upload and deletion completed or stopped." >> "$LOG_FILE"
```
4時間以上かかっていたのが30分ほどになり10倍くらい速くなった。並列数はPARALLEL_JOBSで調整できるがMac Studio (M1 Max メモリ64GB)で60で実行するとCPUモニタはこんな感じになる（黒い部分が全くない）。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56191/28dfaaaa-610d-10a7-a239-7d57420eff64.png" width=50%>

処理が終わるとこんな感じ。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56191/2486bb4b-3b32-5e2a-397e-1d3bcdc05e95.png" width=50%>

がんばっていただいてました。