【问题标题】:AWS S3: How to check if a file exists in a bucket using bashAWS S3:如何使用 bash 检查存储桶中是否存在文件
【发布时间】:2023-03-14 08:04:02
【问题描述】:

我想知道是否可以检查某个存储桶中是否有某些文件。

这是我发现的:

Checking if a file is in a S3 bucket using the s3cmd

它应该可以解决我的问题,但由于某种原因,它一直返回该文件不存在,而它确实存在。这个解决方案也有点过时了,没有使用doesObjectExist 方法。

Summary of all the methods that can be used in the Amazon S3 web service

这给出了如何使用此方法的语法,但我似乎无法使其工作。

他们是否希望您创建一个布尔变量来保存方法的状态,该函数是否直接给您输出/抛出错误?

这是我目前在我的 bash 脚本中使用的代码:

existBool=doesObjectExist(${BucketName}, backup_${DomainName}_${CurrentDate}.zip)

if $existBool ; then
        echo 'No worries, the file exists.'
fi

我只使用文件名进行了测试,而不是给出完整路径。但由于我得到的错误是语法错误,我可能只是用错了。

希望有人可以帮助我并告诉我我做错了什么。

!编辑

我最终寻找了另一种方法来做到这一点,因为使用 doesObjectExist 不是最快或最简单的。

【问题讨论】:

  • this 不是您要找的吗?
  • @TachúSalamanca 是的,谢谢!我已经快速阅读了答案,我想我将寻找另一种方法来检查文件是否存在。可能有比使用doesBucketExist 方法更快、更简单的方法。

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


【解决方案1】:

上次我看到性能比较getObjectMetadata 是检查对象是否存在的最快方法。使用 head-object 方法的 AWS cli,例如:

aws s3api head-object --bucket www.codeengine.com --key index.html

返回:

{
    "AcceptRanges": "bytes",
    "ContentType": "text/html; charset=utf-8",
    "LastModified": "Sun, 08 Jan 2017 22:49:19 GMT",
    "ContentLength": 38106,
    "ContentEncoding": "gzip",
    "ETag": "\"bda80810592763dcaa8627d44c2bf8bb\"",
    "StorageClass": "REDUCED_REDUNDANCY",
    "CacheControl": "no-cache, no-store",
    "Metadata": {}
}

【讨论】:

  • 我喜欢这个,因为它还可以验证您正在检查的是一个对象。在这方面使用 aws s3 ls 有点过于宽容了。
  • 对于那些正在寻找IF 声明的人来说,这里是:not_exist=$(aws s3api head-object --bucket "bucket_name" --key "file/path.ext" >/dev/null 2>1; echo $?) if [ $not_exist == 255 ]; then echo "it does not exist" else echo "it exists" fi
【解决方案2】:

根据@DaveMaple 和@MichaelGlenn 的回答,这是我正在使用的条件:

aws s3api head-object --bucket <some_bucket> --key <some_key> || not_exist=true
if [ $not_exist ]; then
  echo "it does not exist"
else
  echo "it exists"
fi

【讨论】:

  • 这似乎回应了响应,有没有办法只分配 $not_exists 变量而不显示结果或错误?
  • 用您喜欢的任何分配替换echo 命令怎么样?
  • 我不确定我是否理解您的意思,或者您误解了我的意思?我并不是说它回声“它不存在”,显然很容易改变。我是说它在回显“它不存在”之前向终端打印“调用 HeadObject 操作时发生错误(404):未找到”。有没有办法阻止它打印 404 消息?
  • @JohnMellor 将&gt; /dev/null 2&gt;&amp;1 添加到第一个命令:aws s3api head-object --bucket &lt;some_bucket&gt; --key &lt;some_key&gt; &gt; /dev/null 2&gt;&amp;1 || not_exist=true
【解决方案3】:

请注意,“aws s3 ls”并不完全有效,即使答案已被接受。它按前缀搜索,而不是按特定的对象键。当有人通过在文件名末尾添加“1”来重命名文件时,我发现了这一点,并且存在性检查仍将返回 True。

(尝试将此添加为评论,但还没有足够的代表。)

【讨论】:

  • 我刚刚注意到这种完全相同的行为,这就是让我想到这个问题的原因。
【解决方案4】:

一种简单的方法是使用aws s3 ls

exists=$(aws s3 ls $path_to_file)
if [ -z "$exists" ]; then
  echo "it does not exist"
else
  echo "it exists"
fi

【讨论】:

  • 对不起,如果我听起来太苛刻了,但由于其他两篇文章中解释的原因,这应该被接受为答案。
  • 如果您有具有相同前缀的文件,此解决方案将无法正常工作。当存储桶s3://bucket/file.txt.gz 中有文件时,s3://bucket/file.txt 将被视为存在。头对象方法可能是正确的方法,但它会迫使您将 s3:// uri 拆分为不同的部分。
【解决方案5】:

我通常使用set -eufo pipefail,以下对我来说效果更好,因为我不需要担心未设置的变量或整个脚本退出。

object_exists=$(aws s3api head-object --bucket $bucket --key $key || true)
if [ -z "$object_exists" ]; then
  echo "it does not exist"
else
  echo "it exists"
fi

【讨论】:

    【解决方案6】:

    此语句将返回 truefalse 响应:

    aws s3api list-objects-v2 \
      --bucket <bucket_name> \
      --query "contains(Contents[].Key, '<object_name>')"
    

    因此,对于问题中提供的示例:

    aws s3api list-objects-v2 \
      --bucket ${BucketName} \
      --query "contains(Contents[].Key, 'backup_${DomainName}_${CurrentDate}.zip')"
    

    我喜欢这种方法,因为:

    • --query 选项使用 JMESPath 语法进行客户端过滤,并详细记录了 here 如何使用它。

    • 由于 --query 选项已内置到 aws cli 中,因此无需安装其他依赖项。

    • 您可以先运行不带 --query 选项的命令,例如:

        aws s3api list-objects-v2 --bucket <bucket_name> 
      

      返回格式良好的 JSON,类似于:

    {
        "Contents": [
            {
                "Key": "my_file_1.tar.gz",
                "LastModified": "----",
                "ETag": "\"-----\"",
                "Size": -----,
                "StorageClass": "------"
            },
            {
                "Key": "my_file_2.txt",
                "LastModified": "----",
                "ETag": "\"----\"",
                "Size": ----,
                "StorageClass": "----"
            },
            ...
        ]
    }
    
    • 这允许您设计一个适当的查询。在这种情况下,您要检查 JSON 是否包含列表 Contents,并且该列表中的项目的 Key 等于您的文件(对象)名称:

      --query "contains(Contents[].Key, '<object_name>')"
      

    【讨论】:

      【解决方案7】:

      在 awscli 中,我们执行 lsgrep

      示例:aws s3 ls s3:// | grep '文件名'

      这可以包含在 bash 脚本中。

      【讨论】:

      • 这可行,但速度很慢,尤其是当文件数很高时。
      【解决方案8】:

      受上述答案的启发,我还使用它来检查文件大小,因为我的存储桶被一些带有 404 答案的脚本破坏了。它需要jq tho。

      minsize=100
      s3objhead=$(aws s3api head-object \
        --bucket "$BUCKET" --key "$KEY" 
        --output json || echo '{"ContentLength": 0}')
      
      if [ $(printf "%s" "$s3objhead" | jq '.ContentLength') -lt "$minsize" ]; then
        # missing or small
      else
        # exist and big
      fi
      

      【讨论】:

        【解决方案9】:

        一个更简单但不像其他 aws s3 api 那样复杂的解决方案是使用退出代码

        aws s3 ls <full path to object>
        

        如果对象不存在,则返回非零返回码。如果存在则为 0。

        【讨论】:

          猜你喜欢
          • 2015-07-27
          • 2020-11-06
          • 1970-01-01
          • 1970-01-01
          • 2016-11-12
          • 2019-11-10
          • 2015-01-14
          • 2020-06-14
          • 1970-01-01
          相关资源
          最近更新 更多