使用 AWS CLI 从 S3 获取最后修改的对象
Posted
技术标签:
【中文标题】使用 AWS CLI 从 S3 获取最后修改的对象【英文标题】:Get last modified object from S3 using AWS CLI 【发布时间】:2015-09-12 18:27:49 【问题描述】:我有一个用例,我以编程方式启动一个 EC2 实例,从 S3 复制一个可执行文件,运行它并关闭实例(在用户数据中完成)。我只需要从 S3 获取最后添加的文件。
有没有办法使用AWS CLI 工具从 S3 存储桶中获取最后修改的文件/对象?
【问题讨论】:
你能不能涉及一门编程语言 CLI 将是最佳选择,因为我计划在实例启动期间将其包含在用户数据中。 您是否使用任何语言使用 s3 进行编程? 有 2M+ 个对象的桶有更好的解决方案吗? 对于很多对象,我认为更好的解决方案是在ObjectCreation
上触发的对象上创建一个Event/Lambda
。使用 s3 cli 或 api 获取 2M+ 个对象中的最后一个对象会更慢。
【参考方案1】:
如果这是一个新上传的文件,您可以使用Lambda 在新的 S3 对象上执行一段代码。
如果你真的需要获取最新的,你可以先用日期命名你的文件,按名称排序,然后取第一个对象。
【讨论】:
很遗憾,这不是一个新上传的文件。我需要上次上传的文件,该文件可以随时上传。【参考方案2】:您可以使用aws s3 ls $BUCKET --recursive
列出存储桶中的所有对象:
$ aws s3 ls $BUCKET --recursive
2015-05-05 15:36:17 4 an_object.txt
2015-06-08 14:14:44 16322599 some/other/object
2015-04-29 12:09:29 32768 yet-another-object.sh
它们按字母顺序按键排序,但第一列是最后修改时间。快速sort
将按日期重新排序:
$ aws s3 ls $BUCKET --recursive | sort
2015-04-29 12:09:29 32768 yet-another-object.sh
2015-05-05 15:36:17 4 an_object.txt
2015-06-08 14:14:44 16322599 some/other/object
tail -n 1
选择最后一行,awk 'print $4'
提取第四列(对象的名称)。
$ aws s3 ls $BUCKET --recursive | sort | tail -n 1 | awk 'print $4'
some/other/object
最后但同样重要的是,将其放入aws s3 cp
以下载对象:
$ KEY=`aws s3 ls $BUCKET --recursive | sort | tail -n 1 | awk 'print $4'`
$ aws s3 cp s3://$BUCKET/$KEY ./latest-object
【讨论】:
精彩的帖子。由于每个命令的解释,特别有用。谢谢。 S3 仅通过键索引对象。如果存储桶有足够的对象,“全表扫描”来查找您正在寻找的对象是不切实际的,那么您需要建立自己的单独索引。我能想到的最懒惰的选择是在你写完之后把最近写的对象的键放在 s3://$BUCKET/current 中,让读者去那里看看他们应该拉哪一个。 只是一个旁注,如果你想为整个“文件夹”做同样的事情,awk
需要选择第二个元素(而不是第 4 个)并且需要--recursive
,例如,KEY=`aws s3 ls $BUCKET --recursive | sort | tail -n 1 | awk 'print $2'` ; aws s3 cp s3://$BUCKET/$KEY ./latest-object --recursive
这不适用于超过 1000 个项目的存储桶,因为这是最多可以返回的 docs.aws.amazon.com/cli/latest/reference/s3/ls.html
这不会对拥有大量对象的存储桶造成问题吗?【参考方案3】:
以下是 bash 脚本,它从 S3 存储桶下载最新文件。我改用 AWS S3 Synch 命令,这样它就不会从 S3 下载文件(如果已经存在)。
--exclude,排除所有文件
--include,包含所有匹配模式的文件
#!/usr/bin/env bash
BUCKET="s3://my-s3-bucket-eu-west-1/list/"
FILE_NAME=`aws s3 ls $BUCKET | sort | tail -n 1 | awk 'print $4'`
TARGET_FILE_PATH=target/datdump/
TARGET_FILE=$TARGET_FILE_PATHlocalData.json.gz
echo $FILE_NAME
echo $TARGET_FILE
aws s3 sync $BUCKET $TARGET_FILE_PATH --exclude "*" --include "*$FILE_NAME*"
cp target/datdump/$FILE_NAME $TARGET_FILE
附言谢谢@大卫默里
【讨论】:
【参考方案4】:aws s3api list-objects-v2 --bucket "bucket-name" |jq -c ".[] | max_by(.LastModified)|.Key"
【讨论】:
如果你以前没见过jq,它是一个json处理器stedolan.github.io/jq 我认为list-objects-v2
对最大项目数有限制,所以如果您的存储桶有更多的对象 - 这可能无法得到准确的答案
docs.aws.amazon.com/cli/latest/reference/s3api/… 声明(在撰写本文时)每页 的最大限制为 1000。另请注意,如果有更多键,则输出将 IsTruncated
设置为 true可以退货。【参考方案5】:
更新答案
过了一会儿有一个小更新,如何做的有点优雅:
aws s3api list-objects-v2 --bucket "my-awesome-bucket" --query 'sort_by(Contents, &LastModified)[-1].Key' --output=text
我们可以通过[-1]
从列表中获取最后一个条目,而不是额外的reverse
函数
旧答案
这个命令只是完成这项工作,没有任何外部依赖:
aws s3api list-objects-v2 --bucket "my-awesome-bucket" --query 'reverse(sort_by(Contents, &LastModified))[:1].Key' --output=text
【讨论】:
优秀。如果还需要对象名匹配某个字符串:--query 'reverse(sort_by(Contents[?contains(Key, `myKey`)], &LastModified))[:1].Key'
--查询在本地执行,因此如果存储桶中的文件超过 1000 个,则不能保证首先获取最后修改的文件。
@GismoRanas 好点。可以应用常规的--filter
选项来减少列表
如果您将查询用双引号而不是单引号括起来,则此选项可在 Windows cmd 中使用。
对于大型存储桶,建议使用分层键命名方案,以便您可以利用--prefix
选项来减少搜索的键列表。以上是关于使用 AWS CLI 从 S3 获取最后修改的对象的主要内容,如果未能解决你的问题,请参考以下文章
AWS S3 CLI - 如何使用存储桶上设置的所有当前策略获取 JSON?