curl URL Globbing 全解:用 `{}` 列表与 `[]` 范围一次批量生成并抓取 URL
2026/9/10 8:33:42 网站建设 项目流程

curl URL Globbing 全解:用{}列表与[]范围一次批量生成并抓取 URL

【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl

本指南以 curl 命令行工具的 URL globbing 机制为主题(文档主体见 docs/cmdline-opts/_GLOBBING.md),系统讲解如何在一条命令行里用{}花括号列表和[]方括号范围批量生成大量 URL,以及如何借助--output的数字/命名引用把展开结果落到不同文件。读完你不仅能熟练写出可复用的批量下载命令,还能从 src/tool_urlglob.c 与 src/tool_operate.c 的源码层面理解语法校验、范围展开与"里程表式"组合生成的真实实现。

URL Globbing 是什么

curl 允许在一个 URL 参数内部写出多个取值,从而一次命令行批量请求多个 URL,这套机制官方称之为 "globbing"(URL 通配/展开):

你可以在 URL 中通过花括号{}内的列表或方括号[]内的范围来指定多个 URL 或 URL 的一部分,curl 称之为 "globbing"。

与 shell 通配符不同,它是curl 自己(在发起请求之前)解析并逐一展开的,因此即使 shell 不做任何扩展、甚至把整条 URL 放进引号,curl 依然能生成一串真实 URL,并按序逐一请求。需要特别说明:这一解析发生在外层curl * URL主调用链中(src/tool_operate.c 中先以glob_url()把带模式串解析为内部结构、再以glob_next_url()逐个产出 URL),与 libcurl 库 API 无关——它是 curl 命令行工具层的便捷能力,文档见 docs/cmdline-opts/url.md 中对命令行多 URL 语义的介绍。

从实现上看,展开引擎把所有模式串解析为一串URLPattern(src/tool_urlglob.h),每个 pattern 记录一种类型:GLOB_SET{}列表)、GLOB_ASCII(字母范围)、GLOB_NUM(数字范围),三类组合起来足以覆盖文档中的全部语法:

typedef enum { GLOB_SET = 1, GLOB_ASCII, GLOB_NUM } globtype;

{}列举多个候选值

最简单的形式是在花括号内用逗号分隔多个候选片段,curl 会为每一个候选值生成一个 URL:

https://fun.example/{one,two,three}.jpg

等价于依次请求:

  • https://fun.example/one.jpg
  • https://fun.example/two.jpg
  • https://fun.example/three.jpg

{}片段可以出现在 URL 的任意位置,不一定只在末尾,也不受协议限制,例如把候选值放在主机名部分的 SFTP 地址同样成立:

sftp://{one,two,three}.example/README

该写法解析为逐一拉取sftp://one.example/READMEsftp://two.example/READMEsftp://three.example/README

从源码看,{}列表由glob_set()实现(src/tool_urlglob.c):它把,分隔的每个片段复制为独立元素存入elem数组,遇到}结束收集;元素允许为空字符串,但紧贴花括号内没有内容(如{one,}不会出错,{}即"空字符串在括号内")会报错,见 src/tool_urlglob.c 对empty string within braces的判定。

[]声明连续范围

方括号用于声明一段连续的序列,包括数字和字母两种:

数字范围,例如下载file1.txtfile100.txt

ftp://ftp.example.com/file[1-100].txt

带前导零的范围。写法上多写几个零即可,curl 会保持位数对齐地补齐前导零:

ftp://ftp.example.com/file[001-100].txt

即请求file001.txtfile002.txtfile100.txt。源码中该行为由数字范围的npad(padding 位数)字段体现:解析时若发现范围以0开头,会统计前导零个数,生成时使用"%0*d"格式按该位宽补零(src/tool_urlglob.c 与 src/tool_urlglob.c)。

字母范围,从头到尾把字母表当作序列:

ftp://ftp.example.com/file[a-z].txt

上述命令生成filea.txtfilez.txt共 26 个 URL。字母范围同样支持大写,但源码校验要求范围两端必须处于同一大小写域且升序合法,否则判定为bad range(src/tool_urlglob.c)。

加步进:每隔 N 个取一个

范围语法支持追加:step指定步长,得到"每第 N 个"取值。数字与字母都适用:

# 取 1、11、21、…、91 https://example.com/file[1-100:10].txt # 取 a、c、e、… 每隔 2 个字母 https://example.com/file[a-z:2].txt

步进在校验与生成两层都被实现:解析阶段记录step并据此计算展开数量(src/tool_urlglob.c),展开阶段每次把当前游标+= step直到越过max(src/tool_urlglob.c)。注意源码同时对步长做了合法性约束:min == max时步长必须为 1,且step不能超过max - min,违反即报bad range,因此请勿写出[1-5:10]这类语义无意义的模式。

嵌套不支持,但可并列组合

glob 语法不支持嵌套——即不能在{}里再写{}/[],也不能在[]里嵌套。如果你写了嵌套,curl 会直接报错。对应源码中,glob_set()扫描到{[会返回nested brace错误(src/tool_urlglob.c)。

不过你可以把多个 glob 一个挨一个地并列书写,它们会被做笛卡尔积式的组合展开,效果上等价于嵌套。官方示例同时演示了三个相邻 glob:

https://example.com/archive[1996-1999]/vol[1-4]/part{a,b,c}.html

该 URL 一共会展开为4 × 4 × 3 = 48个 URL(1996~1999 四个年份 × vol1~4 四个卷 × part a/b/c 三个分支)。从 src/tool_urlglob.c 的glob_next_url()可看到组合的具体驱动方式:它维护每个 pattern 的当前游标,像里程表/计数器一样从最右侧 pattern 开始递增,走到末尾就回绕并把"进位"传给左边一个 pattern;当最左侧 pattern 也发生回绕时全部组合耗尽。顺序上先保持左侧取值不动、最右侧变化最快,逐条产出。

由于展开数量 = 各 glob 规模的乘积,源码在解析阶段对总数量做乘法和溢出保护multiply(),src/tool_urlglob.c),单个列表元素超过 100000 也会以range overflow报错——实际使用中请避免一次性展开几十万条 URL。

引号与 shell 干扰问题

在命令行直接写含[]{}的 URL 时,bash/zsh 等 shell 可能先于 curl 对它们做通配展开或语法解析(例如中括号恰好匹配到当前目录下的文件,花括号被 shell 当作 brace expansion),从而破坏你的本意。因此官方建议:当 URL 中用到[]/{}序列时,把完整 URL 用双引号包起来

curl "https://fun.example/{one,two}.jpg"

该告诫同样适用于 URL 中出现的其他 shell 特殊字符,例如&?*。把 URL 放入双引号后,shell 不再干预,curl 才能可靠地拿到原始模式串。更稳妥的做法是把它写进配置文件(--config)或脚本变量再引用。

--output复用展开片段:#N位置引用

当一次展开抓取多个 URL 时,默认所有响应会拼接输出到 stdout,几乎没法用。curl 的--output-o)选项因此内置了glob 片段引用语法:在输出文件名里写#加数字,该数字对应 URL 中第 N 个(从 1 开始计数)glob 片段,会被替换为"当前这一条 URL 正在使用的那个取值"。典型例子见 docs/cmdline-opts/output.md:

curl "http://{one,two}.example.com" -o "file_#1.txt"

这条命令分别把one.example.comtwo.example.com的响应保存为file_one.txtfile_two.txt

也可以一次引用多个片段、并且把片段拼在输出文件名任意位置

curl "http://{site,host}.host[1-5].example" -o "#1_#2"

这里#1对应{site,host}#2对应[1-5],于是产出site_1site_2host_5等一组文件。多 URL + 多-o时,两者的对应规则是按位置配对:第几条 URL 就用第几个-o(即文档所说 first-ois for the first URL),且命令行书写顺序无关,URL 与选项可任意混排,见 docs/cmdline-opts/output.md 中-o aa example.com -o bb example.net的等价两种写法。

内部实现上,输出文件名模板的解析在glob_match_url()中完成(src/tool_urlglob.c):遇到#后紧跟数字时,它会解析出序号、寻找globindex匹配的那个 pattern,并把当前展开值注入文件名;若该序号没有对应 glob(比如编号为 0 或越界),则按普通字符原样保留。

8.21.0 起的命名 glob:{<name>one,two}#<name>

curl 8.21.0开始,每个独立的 glob 部分还可以显式命名并在--output按名字引用。名字是区分大小写的字母数字串,写法是在{[之后、紧跟一对尖括号<...>

https://fun.example/{<number>one,two}.jpg ftp://ftp.example.com/file[<range>1-100].txt

随后输出文件名即可通过#<名字>引用对应片段:

curl "https://fun.example/{<num>one,two}.jpg" -o "save-#<num>" curl "ftp://ftp.example/file[<range>1-100].txt" \ -o "save-#<range>.txt"

命名引用比数字引用更可读、也更健壮:即使 URL 中 glob 的数量或次序调整,只要名字不变,-o引用依然准确。需要注意:

  • 同一个 glob 名字重复定义两次是错误,解析阶段会报Duplicate glob name(见 src/tool_urlglob.c);
  • 名字长度上限为 64 字符(MAX_GLOBNAME_LEN,src/tool_urlglob.c);
  • -o中引用了不存在的名字会报错no glob exists with this name,src/tool_urlglob.c),而数字引用越界时则被宽容地按普通字符保留。

命名 glob 的查找按大小写敏感比较完成(glob_find_name(),src/tool_urlglob.c),查找范围同时覆盖 URL 的 glob 列表与上传文件名的 glob 列表——这正是下面的上传场景能跨参数引用的原因。

上传文件名同样支持 globbing

--upload-file-T)的本地文件名参数也支持这套 globbing 语法,因此可以"上传多个文件到同一个 URL";其中命名的 glob 片段还能用于-o里为每个上传请求单独保存响应。官方示例(docs/cmdline-opts/upload-file.md、docs/cmdline-opts/output.md):

curl -T 'file{<num>1,2,3}' \ https://upload.example/ -o 'response-#<num>'

该命令把file1file2file3依次上传到https://upload.example/,并把三次响应分别写入response-1response-2response-3。实现上,上传文件名模式会单独解析到state->inglob,URL 模式解析到state->urlglob(两个结构并存在 src/tool_cfgable.h),glob_match_url()查找命名 glob 时依次检索这两个列表(src/tool_urlglob.c),因此-T里定义的名字才能被-o正确解析到。

关闭 globbing:--globoff-g

某些 URL 会天然包含{}[]字符——虽然按 URI 标准它们并非合法 URL 字符、本应做百分号编码,但现实中你仍可能收到这样的地址。若不想让 curl 展开,可关闭 globbing:

curl -g "https://example.com/{[]}}}}"

--globoff(短选项-g,自 7.6 引入,详见 docs/cmdline-opts/globoff.md)让 curl 把整条 URL 当作普通字面量、不做任何{}/[]展开。设置后 URL 中出现的{}[]都会被原样传送,而不会触发列表/范围解析或各种 "unmatched brace" 之类的报错。

一个与之配套的贴心细节是:数字形式的 IPv6 地址天然使用[...]括起来,curl 能自动识别并放行这类字面量,把它们从 globbing 处理中排除(见 docs/cmdline-opts/globoff.md)。源码中peek_ipv6()会扫描潜在的 IPv6 字面量——它含两个以上冒号且不含连字符,因此明显区别于"含一个连字符的数字范围";识别为 IPv6 后整段[...]会被跳过、不参与范围解析(src/tool_urlglob.c 与 src/tool_urlglob.c),所以curl "http://[::1]/"这类命令无需-g也能正常工作。

常见错误与调试提示

解析失败时 curl 会报curl: (3) ...(URL 格式错误类)并尽可能指示出错位置glob_show_error()会把错误消息连同列位置一并打印,并在 URL 原文下方用^指向出错字符(src/tool_urlglob.c)。下面是可能遇到的代表性错误消息及含义:

报错消息触发场景修复建议
unmatched brace{}有头无尾检查是否缺少}
nested brace{}/[]里嵌套写了{}[]改成并列的多个 glob
unmatched close brace/bracket单独出现多余的}]检查括号配对或用--globoff
bad range[内不是合法数字/字母范围,或范围降序、步长超界检查[min-max][a-z]写法与步长
range overflow展开数量超过上限或乘法溢出缩小范围/列表规模
Duplicate glob name同一个<name>定义了两次改不同的名字
no glob exists with this name-o引用了未定义的名字在 URL/上传文件名中定义该名字

若只是不想让某条含特殊字符的 URL 触发展开,直接加-g即可。

结合测试理解行为

仓库的集成测试直接用真实 URL 验证了上述行为,可作为你排查问题的对照基准:

  • tests/data/test74:{}列表检索 +-o "dumpit#1.dump"数字引用的端到端用例;
  • tests/data/test75:[]范围写错(bad range)时应有的报错行为;
  • tests/data/test86:[]范围检索 +-o #N引用的组合;
  • tests/data/test87:-o #N引用编号越界时的处理。

小结

curl 的 URL globbing 是命令行批量抓取的高效工具,核心要点可归纳为四点:{}做离散列表、[]做数字/字母连续范围(可前导补零、可步进)、相邻 glob 做笛卡尔积组合、用-o "#N"/-o "#<name>"把展开值映射到独立文件。语法解析、范围校验与"里程表式"的展开都在 src/tool_urlglob.c 中实现,理解了它,你既能写出稳健的批量命令(注意 shell 引号与--globoff),也能在遇到报错时快速定位是哪一段模式写得不合规范。

若想继续深挖,相关实现与文档入口为:

  • 官方语法文档主体:docs/cmdline-opts/_GLOBBING.md
  • 命令行引用文档:docs/cmdline-opts/output.md、docs/cmdline-opts/globoff.md、docs/cmdline-opts/upload-file.md、docs/cmdline-opts/url.md
  • 核心实现:src/tool_urlglob.c、src/tool_urlglob.h、调用方 src/tool_operate.c
  • 集成测试:tests/data/test74、tests/data/test75、tests/data/test86、tests/data/test87

【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询