aws s3 ls があるなら aws s3 cat も実行したい、けど無理そうなので aws s3cat で我慢した

aws s3 cat は無理ですが aws s3cat や aws s3_cat や aws s3-cat なら実現できます

S3 オブジェクトの中身をローカルにダウンロードせずに参照したい

コンバンハ、千葉(幸)です。

aws s3 cat を実行したい、そんな風に思ったことはありませんか?つまりは S3 オブジェクトの中身を参照するためにいちいちローカルにダウンロードしたくない、ということです。

例えばこんなふうに aws s3 ls で S3 バケットの中身を参照して……

$ aws s3 ls chibayuki-hoge-hoge/chibayuki/
2022-02-13 13:17:45          0 
2022-02-13 13:19:15         17 test.txt
2022-02-13 13:19:16         17 test2.txt
2022-02-13 13:19:16         17 test3.txt

そのまま aws s3 cat でオブジェクトの中身を表示させたい、ということです。

$ aws s3 cat chibayuki-hoge-hoge/chibayuki/test.txt
hello
hello
hello

できたらいいですよね。aws s3 cp s3://<s3のパス> <ローカルのパス>でローカルにダウンロードしてからそれを開く、というのはめんどくさいですもんね。

で、近いところまで行けました。aws s3 catではなくaws s3cat(半角スペースが入らない)で実現しています。

aws_s3cat

勘のいいみなさんならどうやって実現したらいいかアタリがついたかも知れません。

分からない方のために、どうやって aws s3cat してるんだ というのを書いていきます。

aws s3cat の種明かし

以下を組み合わせて実現しています。

標準出力への S3 オブジェクトのストリーミング

以下のように aws s3 cp においてローカルのパスに-を指定することでストリーミングできます。

aws s3 cp s3://mybucket/stream.txt -

AWS CLI エイリアス

以下のように AWS CLI エイリアスを設定しています。

~/.aws/cli/alias

[toplevel]
 s3cat=
  !f() {
    aws s3 cp s3://${1} -
  }; f

AWS CLI での S3 Streaming

繰り返しになりますが、以下コマンドで S3 オブジェクトをローカルの標準出力にストリーミングでダウンロードできます。

aws s3 cp s3://mybucket/stream.txt -

これは AWS CLI のリファレンスにも載っています。

上記のリファレンスは AWS CLI v2 のものですが、v1 でも同じことができます。DevelopersIO でも 2015 年にすでに取り上げられていました。

標準出力に渡されているので、パイプして繋いであげればgunzipでもgrepでもjqでもpbcopyでも何でもできます。便利ですね。

アップロードでもストリーミングできる

ダウンロードの場合は以下構文でした。

aws s3 cp s3://mybucket/stream.txt -

引数の順番を入れ替えてあげればアップロードもできます。

aws s3 cp - s3://mybucket/stream.txt

以下のようにヒアドキュメントを使ってあげれば複数行の内容も渡せます。

$ cat << EOF | aws s3 cp - s3://chibayuki-hoge-hoge/chibayuki/test4.txt
> test
> test
> test
> EOF
$ aws s3 cp s3://chibayuki-hoge-hoge/chibayuki/test4.txt -
test
test
test

覚えておくと便利そうですね。

S3 上のオブジェクトをストリーミングでダウンロードして zip してアップロードする、なんてお洒落なコマンド例もドキュメントに載っていました。

aws s3 cp s3://bucket-name/pre - | bzip2 --best | aws s3 cp - s3://bucket-name/key.bz2

AWS CLI エイリアスを使う

ここまでで、 S3 オブジェクトをローカルにダウンロードすることなく中身を参照する方法が分かりました。

とは言えもうちょっとシンプルに実行したいものです。s3://を毎回書くのはめんどくさい気がしますものね。

と言うことで AWS CLI エイリアスを使います。AWS CLI エイリアスは「頻繁に使用するコマンドやスクリプトを短縮するために AWS CLI で作成できるショートカット」であると説明されています。

そこまで複雑なものではないので、以下を見ればすぐ理解できるかと思います。

AWS CLI エイリアスの前提条件

  • AWS CLI がインストール済みであること
  • AWS CLI のバージョンが 1.11.24 以上か 2.0.0 以上であること
  • bash スクリプトエイリアスを使用する場合は bash 対応ターミナルであること

1.11.24 は 2016 年に登場したバージョンなので、よっぽど古いものでない限りは対応していると思います。

今回わたしは AWS CloudShell で試したのですが、2022年2月15日現在で以下のバージョンでした。

[cloudshell-user@ip-10-0-15-122 ~]$ aws --version
aws-cli/2.4.15 Python/3.8.8 Linux/4.14.252-195.483.amzn2.x86_64 exec-env/CloudShell exe/x86_64.amzn.2 prompt/off

AWS CLI エイリアスファイルの作成

以下のファイルを作成し、そこに構文を書いてあげればエイリアスが使用できます。

~/.aws/cli/alias

エイリアスファイルの一行目には以下を記載してあげる必要があります。

[toplevel]

CloudShell であればホームディレクトリで以下を実行してあげればOKです。

$ mkdir -p ~/.aws/cli
$ echo '[toplevel]' > ~/.aws/cli/alias

そこに各種エイリアスを追記していきます。

基本的なコマンドエイリアスの構文は以下です。

aliasname = command [--options]

bash スクリプトエイリアスの場合は以下構文です。

aliasname = 
    !f() {
        script content
}; f

今回の aws s3cat では S3 のパスを引数として渡してあげたいので、以下の書き方にしています。

s3cat=
  !f() {
    aws s3 cp s3://${1} -
  }; f

AWS CLI エイリアスでは aws s3 cat は実現できない

例えば以下のようにエイリアスとしてs3 catを指定したらどうだ?と思いましたが、うまくいきませんでした。

~/.aws/cli/alias

s3 cat=
  !f() {
    aws s3 cp s3://${1} -
  }; f

上記のエイリアスを設定した状態でaws s3 catを実行しても、元々のaws s3コマンドが優先度高く解釈されるので、サブコマンドがおかしいと怒られるだけでした。

$ aws s3 cat chibayuki-hoge-hoge/test.txt

usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
To see help text, you can run:

  aws help
  aws <command> help
  aws <command> <subcommand> help

aws: error: argument subcommand: Invalid choice, valid choices are:

ls                                       | website                                 
cp                                       | mv                                      
rm                                       | sync                                    
mb                                       | rb

aws s3_cataws s3-catなら実現できましたが、ちょっとイケてない気がしたのでやめました。

aws whoami とかも実行しよう

以下に AWS CLI のデベロッパーチームやコミュニティによって作成された AWS CLI エイリアスの例があります。

aws whoamiaws sts get-caller-identityを実行したり、aws list-sgsでセキュリティグループ一覧を表示したりなど様々なエイリアスが用意されています。

エイリアスの書き方など参考になる部分があるので、普段よく実行するコマンドのエイリアスを用意してみてはいかがでしょうか。

S3 URI はマネジメントコンソールからコピーできる

aws s3cat を使うイメージはついたものの、S3 のパスを打ち込むのはめんどくさい、ということがあるかも知れません。

そんな時にはマネジメントコンソールから S3 URI をコピーしましょう。

上記の例であれば以下がコピーされます。

  • 左下のボタンの場合:s3://chibayuki-hoge-hoge/chibayuki/test.txt
  • 右上のボタンの場合:s3://chibayuki-hoge-hoge/chibayuki/

パスはマネジメントコンソールからチェックして手元で aws s3cat する、という使い方が便利な時があるかも知れません。

ここまでの例では以下のようにs3://も含めてエイリアスを指定しているので、コピーした内容をそのまま引数として指定すると重複してしまいます。 S3 URI のコピーを多く使用するのであれば、エイリアスからs3://を削ってあげるといいでしょう。

~/.aws/cli/alias

s3cat=
  !f() {
    aws s3 cp s3://${1} -
  }; f

aws s3 cat もいつか実装されるだろうか

aws s3 cp でのストリーミングでのダウンロードと AWS CLI エイリアスを組み合わせた aws s3cat のご紹介でした。

両者を組み合わせずそれぞれ単独で使用しても便利な機能ですので、ちょっとした時に思い出して使ってみてはいかがでしょうか。

aws s3 コマンドと言えば高レベルコマンドとも呼ばれ S3 API をいい感じにラップしてくれているコマンドです。標準で aws s3 cat を実装してくれる日が来ると嬉しいな、と思っています。

でもまぁ無いなら無いでそこまで困らないな、とも思っています。あるもので戦っていきましょう。

以上、 チバユキ (@batchicchi) がお送りしました。

追記

はてブのコメントで以下の feature request があることを教えてもらいました。aws s3 cat を使いたい人は多いのですね……。