【问题标题】:Get last modified object from S3 using AWS CLI使用 AWS CLI 从 S3 获取最后修改的对象
【发布时间】:2015-09-12 18:27:49
【问题描述】:

我有一个用例,我以编程方式启动一个 EC2 实例,从 S3 复制一个可执行文件,运行它并关闭实例(在用户数据中完成)。我只需要从 S3 获取最后添加的文件。

有没有办法使用AWS CLI 工具从 S3 存储桶中获取最后修改的文件/对象?

【问题讨论】:

  • 你能不能涉及一门编程语言
  • CLI 将是最佳选择,因为我计划在实例启动期间将其包含在用户数据中。
  • 您是否使用任何语言使用 s3 进行编程?
  • 有 2M+ 个对象的桶有更好的解决方案吗?
  • 对于很多对象,我认为更好的解决方案是在ObjectCreation 上触发的对象上创建一个Event/Lambda。使用 s3 cli 或 api 获取 2M+ 个对象中的最后一个对象会更慢。

标签: amazon-web-services amazon-ec2 amazon-s3


【解决方案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_PATH}localData.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 选项来减少搜索的键列表。
    猜你喜欢
    • 2020-12-16
    • 2020-01-18
    • 1970-01-01
    • 2012-03-29
    • 1970-01-01
    • 1970-01-01
    • 2017-10-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多