[小ネタ]awscli でs3上の複数ファイルを移動する

awscli s3コマンドの--include, --exlcludeオプションを使うと操作対象のキーをワイルドカードで指定することができます。
2021.09.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

朝起きたとき、ふとS3上の大量のファイルを移動したくなることありますよね。今朝の私がそうでした。

やりたいこと

以下のようにバケット上にhello_world_* から始まるファイルが複数あるとき、helloで始まるファイルだけをhello フォルダ以下に移動したいとします。

> aws s3 ls s3://your-bucket/
hello_1.txt
hello_2.txt
hello_3.txt
hello_4.txt
hello_5.txt
world_1.txt
world_2.txt
world_3.txt
world_4.txt
world_5.txt

include,exclude filters

このような場合にはフィルタオプションが便利です。

awsclli s3サブコマンドでは操作対象のキーを—includeおよび—excludeの2つのオプションによってフィルタすることができます。

これらのオプションは複数回指定することができて、後に指定した条件が先に指定した条件に優先されます。

参考: Use of Exclude and Include Filters

フィルター順序の確認

フィルタの挙動を確認するためにいくつかのパターンを試してみます。

includeが先の場合

hello_*.txtにマッチする条件がexcludeにかき消されてしまっていずれのファイルにもマッチしません。

> aws s3 mv s3://your-bucket \
            s3://your-bucket/hello/ \
            --include "hello_*.txt"  \
            --exclude "*" \
            --recursive \
            --dryrun

—excludeが先の場合

includeで指定した条件が優先されるのでhello_*.txt だけにマッチします。これが今回やりたかった操作です。

> aws s3 mv s3://your-bucket \
            s3://your-bucket/hello/ \
            --exclude "*" \
            --include "hello_*.txt"  \
            --recursive \
            --dryrun
(dryrun) move: s3://your-bucket/hello_1.txt to s3://your-bucket/hello/hello_1.txt
(dryrun) move: s3://your-bucket/hello_2.txt to s3://your-bucket/hello/hello_2.txt
(dryrun) move: s3://your-bucket/hello_3.txt to s3://your-bucket/hello/hello_3.txt
(dryrun) move: s3://your-bucket/hello_4.txt to s3://your-bucket/hello/hello_4.txt
(dryrun) move: s3://your-bucket/hello_5.txt to s3://your-bucket/hello/hello_5.txt

—excludeがない場合

—recursive によって全てのファイルが対象になるのでincludeの有無にかかわらず全ファイルがマッチする。

> aws s3 mv s3://your-bucket \
            s3://your-bucket/hello/ \
            --include "hello_*.txt"  \
            --recursive \
            --dryrun
(dryrun) move: s3://your-bucket/hello_1.txt to s3://your-bucket/hello/hello_1.txt
(dryrun) move: s3://your-bucket/hello_2.txt to s3://your-bucket/hello/hello_2.txt
(dryrun) move: s3://your-bucket/hello_3.txt to s3://your-bucket/hello/hello_3.txt
(dryrun) move: s3://your-bucket/hello_4.txt to s3://your-bucket/hello/hello_4.txt
(dryrun) move: s3://your-bucket/hello_5.txt to s3://your-bucket/hello/hello_5.txt
(dryrun) move: s3://your-bucket/world_1.txt to s3://your-bucket/hello/world_1.txt
(dryrun) move: s3://your-bucket/world_2.txt to s3://your-bucket/hello/world_2.txt
(dryrun) move: s3://your-bucket/world_3.txt to s3://your-bucket/hello/world_3.txt
(dryrun) move: s3://your-bucket/world_4.txt to s3://your-bucket/hello/world_4.txt
(dryrun) move: s3://your-bucket/world_5.txt to s3://your-bucket/hello/world_5.txt

> aws s3 mv s3://your-bucket \
            s3://your-bucket/hello/ \
            --recursive \
            --dryrun
(dryrun) move: s3://your-bucket/hello_1.txt to s3://your-bucket/hello/hello_1.txt
(dryrun) move: s3://your-bucket/hello_2.txt to s3://your-bucket/hello/hello_2.txt
(dryrun) move: s3://your-bucket/hello_3.txt to s3://your-bucket/hello/hello_3.txt
(dryrun) move: s3://your-bucket/hello_4.txt to s3://your-bucket/hello/hello_4.txt
(dryrun) move: s3://your-bucket/hello_5.txt to s3://your-bucket/hello/hello_5.txt
(dryrun) move: s3://your-bucket/world_1.txt to s3://your-bucket/hello/world_1.txt
(dryrun) move: s3://your-bucket/world_2.txt to s3://your-bucket/hello/world_2.txt
(dryrun) move: s3://your-bucket/world_3.txt to s3://your-bucket/hello/world_3.txt
(dryrun) move: s3://your-bucket/world_4.txt to s3://your-bucket/hello/world_4.txt
(dryrun) move: s3://your-bucket/world_5.txt to s3://your-bucket/hello/world_5.txt

まとめ

filterオプションはs3の他のサブコマンドでも使用できて、ローカルのファイルにも適用できるようです。

いつもはファイル一覧をgrepやxargsにパイプして操作をしていたのですが、ファイル数が多い場合はこの方がずっと効率がいいし単純になると思います。