Amazon S3で、既存ファイル(オブジェクト)の storage class を変更する方法

CloudBerry Explorer PRO を使えばできることは分かっていましたが、ビンボーなので無料の方法を探してみました。以下、メモです。
まず最初に、あるバケット内部のオブジェクト(キー)をトラバースしながら storage class をダイレクトに変更するコマンドはないことを確認。
次に、S3 API を調べてみた。以下が使えることが分かった。

つまり同じバケット内で、同じ名前で copy 操作を要求すれば良い。(直接ストレージクラスを変更することはできない。明示的にコピーしなくてはいけない。)
さて、これをどうやって発行するかだ。調べてみると、AWS CLI の s3api コマンドが使えることが分かった。

つまり、たとえばバケット b のオブジェクト foo/bar を storage class REDUCED-REDUNDANCY に変更したければ、次のようにコマンドを発行する。

aws s3api copy-object --copy-source b/foo/bar --bucket b --key foo/bar --storage-class REDUCED_REDUNDANCY

さて次は、どうやってファイルをトラバースするか、だ。aws s3 ls コマンドは recursive に動いてくれないので、aws s3api list-objects コマンドを使うしかない。しかし、AWS API では最大で 1000個までのオブジェクトリストしか返してくれないので、pagination という仕組を使って、細切れにリストを得ることになる。具体的には、最初に

aws s3api --output json list-objects --bucket b --max-items 10

のように(例えば)10個だけ取得して、次は

aws s3api --output jsonlist-objects --bucket b --max-items 10 --starting-token None___10

のようにする。コマンドの出力で NEXTTOKEN が返されなくなるまで、これを繰り返す。(実際には、1000個単位にしたほうが良いか?)
さて。プログラムを書いてみるとするかな。

UTF-8 にならないし

うまく行きそうだったが、オブジェクト名に非 ASCII コードが入っているとおかしくなる。。。
まずは、aws cli コマンドの引数で UTF-8 を受けられるようにする。

具体的には、aws コマンドに

reload(sys)
sys.setdefaultencoding("UTF-8")

を追加する。んが、今度は list-objects の JSON 出力が UTF-8 でないことが判明orz
これは、jq というツールを通すのが簡単ぽい。(寄らば大樹の陰)

こんな感じ。

aws s3api list-objects ... | jq '.Contents[].Key'

とか。

後記: もっと簡単な方法を教えてもらった

orz

aws s3 cp --recursive s3://bucket/ s3://bucket/ --storage-class REDUCED_REDUNDANCY