使用 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 如何确定要同步哪些文件?

AWS S3 CLI - 如何使用存储桶上设置的所有当前策略获取 JSON?

text 通过CLI获取AWS S3存储桶的内容

无法使用 boto 从 S3 读取密钥,但可以使用 aws cli

从AWS S3获取对象作为流

快速获取AWS S3对象元数据