日常用 curl 做网站巡检时,-w 参数输出的性能数据往往是多行字符串,读起来费劲,交给程序处理更是一堆字符串切割的脏活累活。实际上只需要加一个 jq,就能把原本杂乱的输出变成干净的 JSON,程序解析省心,导出报告也方便。这篇文章就来讲讲怎么把 curl -w 的输出交由 jq 处理成结构化 JSON。
一、curl -w 输出到底是什么
curl 的 -w(--write-out)参数用于在请求结束后,按照指定格式输出统计指标。常见变量有:
time_namelookup— DNS 解析耗时time_connect— TCP 连接建立耗时time_starttransfer— 首字节到达耗时(TTFB)time_total— 请求总耗时http_code— HTTP 状态码url_effective— 最终请求 URLnum_redirects— 重定向次数
默认输出是一行键值对字符串,形如 "key1=value1 key2=value2 ..."。同时输出多个变量时,看起来是这样:
time_namelookup: 0.012
time_connect: 0.034
time_starttransfer: 0.089
time_total: 0.145
http_code: 200
这种格式用眼睛看还算直观,但交给程序处理就得写正则解析。换个写法,让 curl 直接输出 JSON 格式,再用 jq 提取,就干净多了。
二、让 curl -w 直接输出 JSON
curl 支持用 %{json} 格式符直接将所有指标以 JSON 格式输出。用法很简单:
curl -s -o /dev/null -w "%{json}" https://www.youres.cn
输出示例:
{"url":"https://www.youres.cn","http_code":200,"time_namelookup":0.005,"time_connect":0.021,"time_starttransfer":0.065,"time_total":0.082,"num_redirects":0}
这是一行标准 JSON 字符串。但需要注意 curl 默认输出的 JSON 不是标准 RFC 8259 格式,某些特殊字符未做转义,直接丢给 jq 有时会报错。更稳妥的做法是自己在 -w 格式字符串里构造 JSON。
三、用 jq 格式化 curl -w 输出
标准做法是让 curl 输出键值对,然后通过 jq 重新组装成标准 JSON。核心思路分两步:
第一步:用 \\n 分隔每个指标,输出形如 "key=value" 的多行
curl -s -o /dev/null -w "time_namelookup=%{time_namelookup}\\ntime_connect=%{time_connect}\\ntime_starttransfer=%{time_starttransfer}\\ntime_total=%{time_total}\\nhttp_code=%{http_code}\\n" https://www.youres.cn
输出:
time_namelookup=0.005
time_connect=0.021
time_starttransfer=0.065
time_total=0.082
http_code=200
第二步:交给 jq 读取每行,用 split("=") 提取键值,重组成 JSON 对象
... | jq -Rs "split(\"\\n\") | map(select(length > 0)) | map(split(\"=\")) | map({\"key\": .[0], \"value\": .[1]}) | from_entries"
输出:
{
"time_namelookup": "0.005",
"time_connect": "0.021",
"time_starttransfer": "0.065",
"time_total": "0.082",
"http_code": "200"
}
到这里就已经得到标准 JSON 了。jq 的 -R 参数读取原始字符串(不当作 JSON 解析),-s 把多行合并为一个数组,from_entries 把键值对数组直接转成 JSON 对象。
数值型指标默认是字符串,可以在 jq 里加一步类型转换:
... | jq "to_entries | map({key, value: (.value | tonumber? // .value)}) | from_entries"
四、批量检测时配合 jq 生成 JSON 数组
做网站批量巡检时,常见的做法是把每台服务器的结果追加到日志文件。用 jq 配合 awk 可以在追加时直接输出 JSON 数组,方便后续导入数据库或可视化工具。
#!/bin/bash
DOMAINS=("www.youres.cn" "example.com" "test.org")
RESULTS=()
for domain in "${DOMAINS[@]}"; do
DATA=$(curl -s -o /dev/null -w "domain=$domain\\ntime_total=%{time_total}\\nhttp_code=%{http_code}\\n" "https://$domain" | jq -Rs "split(\"\\n\") | map(select(length > 0)) | map(split(\"=\")) | map({\"key\": .[0], \"value\": .[1]}) | from_entries")
RESULTS+=("$DATA")
done
printf "%s\\n" "${RESULTS[@]}" | jq -s "."
jq -s "." 把每行 JSON 对象合并成一个 JSON 数组,最终输出:
[
{"domain": "www.youres.cn", "time_total": "0.082", "http_code": "200"},
{"domain": "example.com", "time_total": "0.231", "http_code": "301"},
{"domain": "test.org", "time_total": "1.203", "http_code": "0"}
]
这个数组可以直接 jq ".[] | select(.http_code | tonumber > 399)" 筛选异常,也可以 jq -c ".[] | {domain, time_total}" 只取关键字段。
五、把 JSON 数据导出为 CSV 格式
很多运维同学习惯用 Excel 看巡检数据。用 jq 的 @csv 输出器可以直接导出 CSV,Excel 打开即用:
curl -s -o /dev/null -w "domain=$domain\\ntime_total=%{time_total}\\nhttp_code=%{http_code}\\n" "https://$domain" | jq -Rs "split(\"\\n\") | map(select(length > 0)) | map(split(\"=\")) | map({\"key\": .[0], \"value\": .[1]}) | from_entries | [.domain, .http_code, .time_total] | @csv"
输出直接是标准 CSV 格式,保存到文件后无需额外转换。
六、常见问题排查
问题一:jq 报错 "invalid JSON"
curl -w 输出的值里如果包含引号或特殊字符,会破坏 JSON 格式。解决方案是让 jq 用 from_entries 自动处理转义,不要手动拼字符串。
问题二:某个指标为空
某些情况下 curl 的某个时间变量可能为空值,导致 split 后出现空键。用 map(select(. != "")) 在转 JSON 前过滤空行。
问题三:批量时内存占用高
用 jq -s 读取全部结果再合并,文件过大会吃内存。建议改用 jq -c 每行单独输出,然后在 Python 或其他脚本里做流式追加。
七、总结
curl -w 配合 jq 的核心价值在于把散乱的文本输出变成结构化数据。思路其实很直接:先用固定分隔符把 curl 输出整理成键值对文本,再用 jq 解析重组为标准 JSON。掌握这个套路之后,不管是一次性检测还是定时巡检,都可以直接输出 JSON 数组,数据流转后续的告警、可视化、数据库入库都能顺畅对接。
日常运维中推荐把这个套路封装成 Shell 函数:
function curl_json() {
local url=$1
curl -s -o /dev/null -w "url=${url}\\nhttp_code=%{http_code}\\ntime_total=%{time_total}\\ntime_namelookup=%{time_namelookup}\\ntime_connect=%{time_connect}\\ntime_starttransfer=%{time_starttransfer}\\n" "$url" | \\
jq -Rs "split(\"\\n\") | map(select(length > 0)) | map(split(\"=\")) | map({\"key\": .[0], \"value\": .[1]}) | from_entries"
}
# 用法
curl_json "https://example.com" | jq ".http_code"
一行命令搞定结构化输出,curl 和 jq 各司其职,简单实用。
相关文章:
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论