S3 バケットから複数のファイルを一括でコピーする

はじめに

 AWS コマンドはLinux の標準コマンドによく似た引数の並びで S3 へ簡単にアクセスできるようになっています。しかし完全に同じというわけではなく、例えば aws s3 cp コマンドでアスタリスクを付けてコピーしようとしても、ワイルドカードとして認識されず失敗します。

$ aws s3 cp s3://my-bucket/json-data* /mnt/.
A client error (404) occurred when calling the HeadObject operation: Key "json-data*" does not exist
Completed 1 part(s) with ... file(s) remaining

 今回、BashとPython3 (+ boto3)で複数ファイルの取り扱いについて紹介したいと思います。

特定のディレクトリ全体を対象にする

Bash サンプル

 rsyncのように一括でコピーできます。末尾のスラッシュを明示的に付けて「ディレクトリ同士のコピーですよ」と明示する、と覚えるといいかと思います。下記のサンプルの場合、S3上のディレクトリs3dirとローカルのディレクトリlocaldirは同じ構造になります。

$ aws s3 sync s3://my-bucket/s3dir/ /mnt/localdir/ \
      --exclude "*" \
      --include "json-data*"

コピーするファイルのリストを使う

Bash サンプル

 リストを一覧で取得してから、目的のファイルのみを抽出して for do done ループで処理します。

$ LIST=$(aws s3 ls s3://my-bucket/ | grep json-data | awk '{print $4}')
$ for ITEM in $LIST
  do
      aws s3 cp s3://my-bucket/$ITEM /mnt/
  done

Python3 サンプル

 Python3 では boto3 パッケージを利用してファイルをコピー(ダウンロード)します。Python3 及び venv 環境の構築はこちらの投稿を参照してください。

(venv35)$ pip install boto3
s3-cp.py
import boto3
import os

bucketname = 'my-bucket'
keyword = 'json-data'
saveto = '/mnt'

s3client = boto3.resource('s3')
bucket = s3client.Bucket(bucketname)
objects = bucket.objects.all()
for a_object in objects:
    if keyword in a_object.key:
        # Preparing to copy.
        savetopath = '{0}/{1}'.format(saveto, a_object.key)
        directory = os.path.dirname(savetopath)
        if not os.path.exists(directory):
            os.makedirs(directory)
        # Copy.
        bucket.download_file(a_object.key, savetopath)
(venv35)$ python s3-cp.py

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください