URI 通配符

Google Cloud CLI 支持将 URI 通配符用于文件、存储桶和对象。通配符使您可以高效地使用与指定命名模式匹配的文件组。本页面介绍了受支持的通配符,并指明了在命令中使用通配符时的重要注意事项。

通配符字符

gcloud CLI 支持以下通配符:

字符 说明
* 匹配当前目录级别中的零个或更多字符。例如,cp gs://my-bucket/abc/d* 与对象 abc/def.txt 匹配,但与 abc/def/g.txt 对象不匹配。对于列出命令(例如 ls)的情况,如果尾随 * 与当前目录级别中的子目录匹配,则还会列出子目录的内容。
** 匹配目录边界内的零个或更多字符。用作本地文件路径的一部分时,** 通配符应始终以目录分隔符开头。例如,my-directory/**.txt 有效,但 my-directory/abc** 无效。
? 匹配单个字符。例如,gs://bucket/??.txt 仅匹配两个字符后跟 .txt 的对象。
[CHARACTERS] 匹配任何指定字符。例如,gs://bucket/[aeiou].txt 匹配包含一个单元音字符后跟 .txt 的对象。
[CHARACTER_RANGE] 匹配任何字符范围。例如,gs://bucket/[a-e].txt 匹配包含字母 a、b、c、d 或 e 后跟 .txt 的对象。

您可以组合通配符来提供更强大的匹配功能,例如:

gs://*/[a-m]??.j*g

请注意,除非您的命令包含在结果中返回非当前对象版本的标志,否则这些通配符只能与活动对象版本匹配。

gcloud CLI 支持对象和文件名使用相同的通配符。因此,例如:

gcloud storage cp data/abc* gs://bucket

匹配本地文件系统的 data 目录中以 abc 开头的所有文件。

行为注意事项

在以下几种情况下,使用通配符可能会导致意外行为:

  • 在存储桶名称中使用通配符时,匹配项仅限于单个项目中的存储桶。许多命令都允许您使用标志指定项目。如果命令不包含项目标志或不支持使用项目标志,则匹配项仅限于默认项目中的存储桶。

  • Shell(如 bash 和 zsh)会尝试在将参数传递给 gcloud CLI 之前扩展通配符。如果通配符应该引用云对象,这可能会导致意外的“未找到”错误。例如,shell 可能会尝试扩展本地机器上的通配符 gs://my-bucket/*,它不会匹配任何本地文件,从而导致命令失败。

    此外,某些 shell 的通配符字符集中包含其他字符。例如,如果您在启用 extendedglob 选项的情况下使用 zsh,它会将 # 视为特殊字符,这与引用有版本控制的对象时该字符的使用形成冲突(请参阅恢复非当前对象版本中的示例)。

    为避免这些问题,请使用英文单引号(Linux 上)或英文双引号(Windows 上)括住通配符表达式。

  • 尝试指定包含通配符字符的文件名时操作无效,这是因为命令行工具将试着扩展通配符字符,而不是以字面量字符的形式使用通配符。例如,运行命令:

    gcloud storage cp './file[1]' gs://my-bucket

    永远不会复制名为 file[1] 的本地文件。gcloud CLI 始终将 [1] 视为通配符。

    gcloud CLI 不支持“原始”模式,该模式允许使用包含通配符的文件名。对于此类文件,您应使用其他工具(如 Google Cloud 控制台)或使用通配符来捕获文件。例如,如需捕获名为 file[1] 的文件,您可以使用以下命令:

    gcloud storage cp './file*1*' gs://my-bucket
  • 根据标准的 Unix 行为,通配符 * 仅匹配不以 . 字符开头的文件(以避免与所有 Unix 目录中存在的 ... 目录混淆)。对文件系统 URI 使用通配符时,gcloud CLI 提供此相同行为,但对 Cloud URI 使用通配符时不提供此行为。例如,以下命令会将 gs://bucket1 中的所有对象复制到 gs://bucket2

    gcloud storage cp gs://bucket1/* gs://bucket2

    但是,以下命令仅将目录 dir 中不以 . 开头的文件复制到 gs://bucket1

    gcloud storage cp dir/* gs://bucket1

效率注意事项

  • 下面两种方法相比,前者更高效、快速,且密集型网络流量更少,它使用具有非通配符对象名称前缀的通配符,例如:

    gs://bucket/abc*.txt

    第二种方法将通配符用作对象名称的第一部分,例如:

    gs://bucket/*abc.txt

    这是因为 gs://bucket/abc*.txt 请求要求服务器发送回存储桶根目录中对象名称以 abc 开头的结果的子集,然后过滤结果列表以得到名称以 .txt 结尾的对象。相比之下,gs://bucket/*abc.txt 要求服务器提供存储桶根目录中对象的完整列表,然后过滤获取名称以 abc.txt 结尾的对象。当您使用包含数千个或更多对象的存储桶时,这种效率考量会愈加明显。有时,您可以设置对象的名称,使其符合预期的通配符匹配模式,从而利用进行服务器端前缀请求的效率。

  • 假设您有一个包含以下对象的存储分区:

    gs://bucket/obj1
    gs://bucket/obj2
    gs://bucket/obj3
    gs://bucket/obj4
    gs://bucket/dir1/obj5
    gs://bucket/dir2/obj6

    如果您运行以下命令:

    gcloud storage ls gs://bucket/*/obj5

    gcloud storage 会执行 / 分隔的顶层存储分区列出,然后针对每个子目录执行一次存储分区列出,总共 3 次存储分区列出:

    GET /bucket/?delimiter=/
    GET /bucket/?prefix=dir1/obj5&delimiter=/
    GET /bucket/?prefix=dir2/obj5&delimiter=/
    

    通配符要求的存储分区列出越多,其速度越慢,费用也就越高。所需存储分区列出的次数会随下列因素增加:

    • 通配符元素的数量(例如 gs://bucket/a??b/c*/*/d 包含 3 个通配符元素);

    • 与每个元素匹配的子目录的数量;以及

    • 结果的数量(当结果数量过大时,系统会实现分页,并为每个请求指定标记)。

    如果要使用路径中间通配符,您可以尝试改用递归通配符,例如:

    gcloud storage ls gs://bucket/**/obj5

    它匹配的对象将比 gs://bucket/*/obj5(因为它跨目录)更多,但会使用分隔符更少的存储分区列出请求(这意味着存储分区请求减少,但它会列出整个存储分区并进行本地过滤,因此可能需要大量的网络流量。)