便利だったのでメモ。

やりたいこと

以下のように特定のバケットにあるファイルから最新のファイル名を1つ取得したい。

> aws s3 ls s3://<バケット名>/

2019-11-26 09:01:32          0 hoge1.txt
2019-11-26 09:01:54          0 hoge2.txt
2019-11-26 09:01:25          0 hoge3.txt
2019-11-26 09:01:46          0 hoge4.txt
2019-11-26 09:01:39          0 hoge5.txt

# 「hoge2.txt」がほしい

> <いい感じのコマンド>

hoge2.txt

aws s3 lsに最終更新日時が含まれているのでできなくはなかろうと思って調べて試してみました。

いい感じのコマンド

> aws s3 ls s3://<バケット名>/ | sort -nr | head -n 1 | awk '{print $NF}'

hoge2.txt

いい感じです。

ポイント

lsコマンドで出力される最終更新日時はPUT開始時間

下記によると最終更新日時はPUT開始時間だそうなので、ファイル作成・更新日時でも、PUT後に参照可能になった時間でもないことに注意しましょう。

S3の最終更新日時(Last Modified)の罠 – Qiita
https://qiita.com/katsuyan/items/bf6f1a06d8148212c057

sort コマンドで並び替え

[aws]s3 lsで取得したファイルを更新日時順でソートする
https://blog.hello-world.jp.net/aws/4254/

nオプションで先頭を数値とみなしてソートすることで更新日時順にソートされます。
また、rオプションで降順にソートしています。

aws s3 lsコマンドの結果をsortコマンドに渡してやればよいとのことでした。

# 昇順
> aws s3 ls s3://<バケット名>/ | sort -n

2019-11-26 09:01:25          0 hoge3.txt
2019-11-26 09:01:32          0 hoge1.txt
2019-11-26 09:01:39          0 hoge5.txt
2019-11-26 09:01:46          0 hoge4.txt
2019-11-26 09:01:54          0 hoge2.txt

# 降順
> aws s3 ls s3://<バケット名>/ | sort -nr

2019-11-26 09:01:54          0 hoge2.txt
2019-11-26 09:01:46          0 hoge4.txt
2019-11-26 09:01:39          0 hoge5.txt
2019-11-26 09:01:32          0 hoge1.txt
2019-11-26 09:01:25          0 hoge3.txt

head コマンドで1行目を取得する

ファイルの先頭から表示するheadコマンドの詳細まとめ【Linuxコマンド集】
https://eng-entrance.com/linux-command-head

headコマンドの-nオプションで出力する行数が指定できるので、それを利用します。

> aws s3 ls s3://<バケット名>/ | sort -nr | head -n 1

2019-11-26 09:01:54          0 hoge2.txt

awk コマンドでファイル名を取得する

最終更新日、日時、ファイルサイズ、ファイル名と並んでいる中からファイル名のみ出力させたい場合、awkコマンドが利用できました。
4番目にあるのでawk '{print $4}'とも指定できますし、最後にあるのでawk '{print $NF}'ともできます。

AWS(Amazon Web Services) – aws S3 lsコマンドでファイル名だけを表示させたい|teratail
https://teratail.com/questions/168264

awk とシェルとの値の受け渡しについて – Qiita
https://qiita.com/shotets/items/b9ebf936b4152ea12aa1

> aws s3 ls s3://<バケット名>/ | sort -nr | head -n 1 | awk '{print $NF}'

hoge2.txt

下層ディレクトリ(キー)にあるファイルもまとめてソートしたい

aws s3コマンドの--recursiveオプションを利用すれば実現できました。

ls — AWS CLI 1.16.291 Command Reference
https://docs.aws.amazon.com/cli/latest/reference/s3/ls.html

下層にあるファイルの場合、ディレクトリ(キー)名が含まれるので、basenameコマンドでファイル名のみ取得することもできます。

【 basename 】コマンド――パス名からファイル名を取得する:Linux基本コマンドTips(177) – @IT
https://www.atmarkit.co.jp/ait/articles/1801/25/news025.html

# ファイルをfooディレクトリ(キー)下に追加
> aws s3 cp hoge6.txt s3://<バケット名>/foo/

> aws s3 ls s3://<バケット名>/ \
  | sort -nr

2019-11-26 09:01:54          0 hoge2.txt
2019-11-26 09:01:46          0 hoge4.txt
2019-11-26 09:01:39          0 hoge5.txt
2019-11-26 09:01:32          0 hoge1.txt
2019-11-26 09:01:25          0 hoge3.txt
                           PRE foo/

> aws s3 ls --recursive s3://<バケット名>/ \
  | sort -nr | head -n 1

2019-11-26 09:23:39          0 hoge/foo/hoge6.txt
2019-11-26 09:01:54          0 hoge/hoge2.txt
2019-11-26 09:01:46          0 hoge/hoge4.txt
2019-11-26 09:01:39          0 hoge/hoge5.txt
2019-11-26 09:01:32          0 hoge/hoge1.txt
2019-11-26 09:01:25          0 hoge/hoge3.txt


> aws s3 ls --recursive s3://<バケット名>/ \
  | sort -nr | head -n 1 | awk '{print $NF}'

foo/hoge6.txt


> basename "$(aws s3 ls --recursive s3://<バケット名>/ \
  | sort -nr | head -n 1 | awk '{print $NF}')"

hoge6.txt

fish shellな方はこちら

> basename (aws s3 ls --recursive s3://<バケット名>/ \
  | sort -nr | head -n 1 | awk '{print $NF}')

hoge6.txt

Windowsな方は、、、ゴメンナサイ。WSL使ってください。

別解

本記事をまとめ終わったあとにorz、Stack Overflowでみかけた別解です。

amazon web services – get last modified object from S3 CLI – Stack Overflow
https://stackoverflow.com/questions/31062365/get-last-modified-object-from-s3-cli

aws s3api list-objects-v2コマンドを利用して--queryオプションで絞り込みます。なるへそ。
こちらは指定せずとも再帰的にファイルを取得してくれました。

> aws s3api list-objects-v2 \
  --bucket "<バケット名>" \
  --query 'reverse(sort_by(Contents, &LastModified))[:1].Key' \
  --output=text

hoge6.txt

参考

S3の最終更新日時(Last Modified)の罠 – Qiita
https://qiita.com/katsuyan/items/bf6f1a06d8148212c057

[aws]s3 lsで取得したファイルを更新日時順でソートする
https://blog.hello-world.jp.net/aws/4254/

ファイルの先頭から表示するheadコマンドの詳細まとめ【Linuxコマンド集】
https://eng-entrance.com/linux-command-head

AWS(Amazon Web Services) – aws S3 lsコマンドでファイル名だけを表示させたい|teratail
https://teratail.com/questions/168264

awk とシェルとの値の受け渡しについて – Qiita
https://qiita.com/shotets/items/b9ebf936b4152ea12aa1

ls — AWS CLI 1.16.291 Command Reference
https://docs.aws.amazon.com/cli/latest/reference/s3/ls.html

【 basename 】コマンド――パス名からファイル名を取得する:Linux基本コマンドTips(177) – @IT
https://www.atmarkit.co.jp/ait/articles/1801/25/news025.html

amazon web services – get last modified object from S3 CLI – Stack Overflow
https://stackoverflow.com/questions/31062365/get-last-modified-object-from-s3-cli

元記事はこちら

AWS CLIでAmazon S3のバケットにあるファイルから最新のファイル名を1つ取得する