0

curl -w @模板文件JSON格式批量检测最佳实践:5步把巡检数据变成结构化JSON

2026.06.15 | youres | 4次围观

批量检测一批URL的状态时,把结果导出为结构化JSON是很多运维同学梦寐以求的能力。JSON格式便于后续程序处理、对接Prometheus、做二次分析。本质上分两步:先让curl输出可解析的格式化文本,再用jq把它变JSON。curl -w @模板文件的作用是让格式化输出规则独立管理,脚本更干净。

一、模板文件到底是什么

curl -w @文件名 的意思是:从指定的文件中读取 write-out 格式化字符串,而不用把长长的格式化参数写在命令行里。比如你在当前目录新建一个文件叫 fmt.txt,内容写:

{"url":"%{url_effective}","status":"%{http_code}","redirects":"%{num_redirects}","time_ms":"%{time_total}"}

然后执行:

curl -sL -w @fmt.txt https://www.youres.cn -o /dev/null

curl 会把模板里的变量替换掉,输出:

{"url":"https://www.youres.cn/","status":"200","redirects":"0","time_ms":"0.123"}

二、直接输出的局限:多行问题

上面这个方法有个坑:如果URL里有换行符,输出会变成多行,jq 就解析不了了。更可靠的做法是:curl 输出用分隔符隔开的原始数据,再交给 jq 统一拼装。

新建模板文件 batch.tmpl

%{url_effective}SEP%{http_code}SEP%{num_redirects}SEP%{time_total}

SEP 作为分隔符(自定义分隔符,避免和URL本身冲突)。

三、最佳实践一:单URL JSON快速验证

最基础的用法,一行命令拿到单URL的JSON格式检测结果:

url="https://httpbin.org/status/200"
raw=$(curl -sL --max-time 10 -w 'SEP%{http_code}SEP%{num_redirects}SEP%{time_total}' "$url" -o /dev/null)
echo "$url$raw" | awk -F'SEP' '{printf "{\"url\":\"%s\",\"status\":%s,\"redirects\":%s,\"time_ms\":%d}\n",$1,$2,$3,int($4*1000)}'

输出:

{"url":"https://httpbin.org/status/200","status":200,"redirects":0,"time_ms":245}

四、最佳实践二:模板文件 + URL列表批量检测

第一步,准备模板文件 check.tmpl:

%{url_effective}SEP%{http_code}SEP%{num_redirects}SEP%{time_total}

第二步,准备URL列表文件 urls.txt(每行一个URL):

https://www.youres.cn
https://httpbin.org/status/200
https://httpbin.org/status/301

第三步,编写批量检测脚本:

#!/bin/bash
TEMPLATE="check.tmpl"
TMPFILE="/tmp/batch_raw.txt"
> "$TMPFILE"

while IFS= read -r url; do
  result=$(curl -sL --max-time 10 -w "@${TEMPLATE}" "$url" -o /dev/null)
  echo "${url}SEP${result}" >> "$TMPFILE"
done < urls.txt

# jq把所有行合并为JSON数组
jq -Rs \
  'split("\n") | map(select(length > 0)) | map(split("SEP") | {url: .[0], status: (.[1] | tonumber), redirects: (.[2] | tonumber), time_ms: (.[3] | tonumber * 1000 | floor)})' \
  "$TMPFILE"
rm -f "$TMPFILE"

运行后会输出一个完整的 JSON 数组,每个元素对应一个URL的检测结果。

五、最佳实践三:并行加速 + JSON汇总

URL多了串行太慢,用 xargs 并行处理:

#!/bin/bash
TEMPLATE="check.tmpl"

cat urls.txt | xargs -P 4 -I {} sh -c '
  url="{}"
  raw=$(curl -sL --max-time 10 -w "@TEMPLATE" "$url" -o /dev/null)
  echo "$urlSEP$raw"
' > /tmp/batch_raw.txt

jq -Rs \
  'split("\n") | map(select(length > 0)) | map(split("SEP") | {url: .[0], status: (.[1] | tonumber), redirects: (.[2] | tonumber), time_ms: (.[3] | tonumber * 1000 | floor)})' \
  /tmp/batch_raw.txt
rm /tmp/batch_raw.txt

并行度 -P 4 表示同时跑4个curl进程,可以根据服务器带宽调整。

六、最佳实践四:JSON输出 + 时间戳和告警字段

实际巡检系统里,只输出状态码不够,需要加上巡检时间和告警判断:

#!/bin/bash
TEMPLATE="check.tmpl"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

while IFS= read -r url; do
  raw=$(curl -sL --max-time 10 -w "@${TEMPLATE}" "$url" -o /dev/null)
  echo "$urlSEP$raw" | jq -R '
    split("SEP") |
    {
      url: .[0],
      timestamp: "'"$TIMESTAMP"'",
      status: (.[1] | tonumber),
      redirects: (.[2] | tonumber),
      time_ms: (.[3] | tonumber * 1000 | floor),
      alert: (if (.[1] | tonumber) >= 400 then "danger"
              elif (.[1] | tonumber) >= 300 then "warning"
              else "ok" end)
    }
  '
done < urls.txt | jq -s .

输出示例:

[
  {
    "url": "https://www.youres.cn",
    "timestamp": "2026-06-15T03:02:00Z",
    "status": 200,
    "redirects": 0,
    "time_ms": 120,
    "alert": "ok"
  },
  {
    "url": "https://httpbin.org/status/404",
    "status": 404,
    "redirects": 0,
    "time_ms": 310,
    "alert": "danger"
  }
]

七、最佳实践五:结果追加写入JSON Lines历史记录

巡检系统需要留存历史记录,每次检测结果追加到一个 JSON Lines 文件(每行一个JSON对象):

#!/bin/bash
TEMPLATE="check.tmpl"
HISTORY="scan_history.jsonl"

while IFS= read -r url; do
  raw=$(curl -sL --max-time 10 -w "@${TEMPLATE}" "$url" -o /dev/null)
  echo "$raw" | jq -Rs \
    'split("SEP") |
     {url: .[0], timestamp: (now | todateiso8601),
      status: (.[1] | tonumber),
      redirects: (.[2] | tonumber),
      time_ms: (.[3] | tonumber * 1000 | floor)}' \
    >> "$HISTORY"
done < urls.txt

JSONL 格式的好处是可以随时合并成数组,也可以用 grep 直接搜索历史记录。

八、模板文件常用变量速查

  • %{url_effective} 最终请求的URL(跟随重定向后)
  • %{http_code} HTTP状态码
  • %{num_redirects} 重定向次数
  • %{time_total} 总耗时(秒)
  • %{time_redirect} 重定向耗时(秒)
  • %{time_namelookup} DNS解析耗时
  • %{time_connect} TCP连接耗时
  • %{time_starttransfer} 首字节耗时
  • %{size_download} 下载字节数

九、Windows PowerShell 版本

Windows 没有原生 jq,用 PowerShell 处理 JSON 更方便:

$results = @()
$urls = Get-Content urls.txt
foreach ($url in $urls) {
    $raw = (curl -sL -TimeoutSec 10 `
        -w 'SEP%{http_code}SEP%{num_redirects}SEP%{time_total}' `
        $url -o `$null) -split 'SEP'
    $obj = @{
        url       = $url
        status    = [int]$raw[1]
        redirects = [int]$raw[2]
        time_ms   = [math]::Round([double]$raw[3] * 1000)
        timestamp = (Get-Date).ToString("o")
    }
    $results += $obj
}
$results | ConvertTo-Json -Depth 3 |
    Out-File -FilePath scan_result.json -Encoding UTF8

总结

用 curl -w @模板文件 做 JSON 批量检测,核心就三步:定格式模板、循环跑curl、用 jq 拼 JSON。模板文件把格式规则从脚本中分离出来,维护更方便;jq 把原始文本变成真正的 JSON 结构。熟练之后,写一个 5 行的巡检脚本就能搞定几十上百个 URL 的自动化检测。


相关阅读:

版权声明

本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论