curl 命令输出格式化指南 – wiki基地


curl 命令输出格式化指南:精炼信息,掌控结果

curl 是一个功能强大的命令行工具,用于传输数据,支持多种协议(如 HTTP, HTTPS, FTP, FTPS, SCP, SFTP, TFTP, DICT, TELNET, LDAP, LDAPS, GOPHER, FILE, RTMP, RTSP, POP3, POP3S, SMTP, SMTPS, IMAP, IMAPS, SMB, SMBS)。它广泛应用于网络调试、自动化脚本、数据下载等场景。

然而,curl 的默认输出有时可能包含大量信息,如进度条、连接详情、下载数据等,这对于自动化处理或只关注特定信息的场景来说显得过于冗余。幸运的是,curl 提供了丰富的选项来控制其输出,让用户能够精确地获取所需信息,并以易于解析或阅读的格式呈现。

本文将深入探讨 curl 的输出格式化技巧,从基础的静默输出到高级的自定义信息提取,帮助您更好地利用 curl

1. 理解 curl 的默认输出

在深入格式化之前,先了解 curl 的默认输出构成是很重要的。通常,一个简单的 curl <URL> 命令会输出:

  1. 下载进度条 (Progress Meter): 显示下载的速度、已下载量、剩余时间等。
  2. 错误或状态信息: 在进度条下方或完成后显示,如连接错误、重定向信息等。
  3. 响应体 (Response Body): 这是最重要的部分,即从服务器获取的数据内容(如网页HTML、JSON数据、文件内容等)。

例如:

bash
curl https://www.example.com

输出可能包含:

“`
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 –:–:– –:–:– –:–:– 0
100 1270 100 1270 0 0 2152 0 –:–:– –:–:– –:–:– 2152




… (网页HTML内容) …

“`

这个默认输出对于交互式使用很友好,但如果要在脚本中只获取 HTML 内容,或者只关心 HTTP 状态码,这些附加信息就变成了干扰。

2. 控制输出的显示级别:静默与详细

curl 提供了控制输出详细程度的基本选项:

2.1 静默模式 (-s, --silent)

-s--silent 选项会完全抑制 curl 的进度条和错误消息(大多数情况下)。这是在脚本中获取纯净响应体最常用的选项。

bash
curl -s https://www.example.com

输出将只有响应体:

“`html




… (网页HTML内容) …

“`

注意: -s 会抑制 大多数 错误消息。如果发生严重的连接错误、DNS查找失败等,它可能仍然会输出一些信息到标准错误 (stderr)。如果需要完全静默,甚至包括错误信息,可以重定向 stderr 到 /dev/null (或 Windows 上的 NUL)。

2.2 显示错误但静默进度条 (-S, --show-error)

当使用 -s 时,如果请求失败,您可能看不到任何错误信息,这使得调试变得困难。-S--show-error 选项通常与 -s 结合使用。它会在使用 -s 时强制 curl 显示错误信息。

“`bash

尝试访问一个不存在的域名,并显示错误

curl -s -S http://this.domain.does.not.exist
“`

输出可能类似:

curl: (6) Could not resolve host: this.domain.does.not.exist

如果没有 -S,在某些情况下,这个错误可能不会显示。

2.3 冗余模式 (-v, --verbose)

与静默模式相反,-v--verbose 选项会输出非常详细的调试信息到标准错误 (stderr)。这些信息包括:

  • 试图连接的IP地址和端口
  • SSL/TLS握手详情
  • 发送的请求头
  • 接收到的响应头
  • 连接状态和数据传输过程

这对于诊断连接问题、查看请求和响应头、理解重定向过程等非常有用。

bash
curl -v https://www.example.com

输出会包含大量以 *, >, < 开头的调试信息(分别表示连接信息、发送的请求头、接收的响应头),最后才是响应体。

“`
* Trying 93.184.216.34:443…
* Connected to www.example.com (93.184.216.34) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
* … (SSL/TLS handshake details) …

GET / HTTP/1.1
Host: www.example.com
User-Agent: curl/7.81.0
Accept: /

< HTTP/1.1 200 OK
< Age: 500000
< Cache-Control: max-age=604800
< Content-Type: text/html; charset=UTF-8
< Date: Thu, 25 Jan 2024 10:00:00 GMT
< Etag: “3147526947+ident”
< Expires: Thu, 01 Feb 2024 10:00:00 GMT
< Last-Modified: Tue, 02 Jan 2024 15:00:00 GMT
< Server: ECS (sec/9300)
< Vary: Accept-Encoding
< X-Cache: HIT
< Content-Length: 1270
<
{ [1270 bytes data]




… (网页HTML内容) …

  • Connection #0 to host www.example.com left intact
    “`

curl -v 是调试网络请求时不可或缺的工具。请注意,调试信息是输出到标准错误流 (stderr) 的,而响应体是输出到标准输出流 (stdout) 的。这使得您可以使用重定向来分离它们,例如 curl -v example.com > body.html 2> debug.log

3. 控制输出的内容:响应头与响应体

除了控制详细程度,您还可以选择 curl 应该输出哪些部分:响应头、响应体,或者两者。

3.1 只显示响应头 (-I, --head)

-I--head 选项会发送一个 HEAD 请求给服务器(而不是默认的 GET)。服务器通常只会返回响应头,而不包含响应体。这是一种快速检查网页是否存在、获取文件大小、查看缓存信息或重定向目标的方式。

bash
curl -I https://www.example.com

输出将只包含响应头:

HTTP/1.1 200 OK
Age: 500000
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Thu, 25 Jan 2024 10:00:00 GMT
Etag: "3147526947+ident"
Expires: Thu, 01 Feb 2024 10:00:00 GMT
Last-Modified: Tue, 02 Jan 2024 15:00:00 GMT
Server: ECS (sec/9300)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 1270

注意: 虽然 -I 发送的是 HEAD 请求,但并非所有服务器都完全支持 HEAD 请求,或者其 HEAD 响应头可能与 GET 请求的响应头略有不同。

3.2 包含响应头和响应体 (-i, --include)

-i--include 选项会在输出响应体之前,先输出完整的响应头。与 -v 不同,-i 只输出响应头,不包含连接过程或请求头等其他调试信息。

bash
curl -i https://www.example.com

输出将包含响应头,然后是响应体:

“`
HTTP/1.1 200 OK
Age: 500000
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Thu, 25 Jan 2024 10:00:00 GMT
Etag: “3147526947+ident”
Expires: Thu, 01 Feb 2024 10:00:00 GMT
Last-Modified: Tue, 02 Jan 2024 15:00:00 GMT
Server: ECS (sec/9300)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 1270




… (网页HTML内容) …

“`

这在需要同时查看服务器响应状态、内容类型、缓存策略等信息,并获取响应体时很有用。

4. 控制输出的目标:标准输出与文件

默认情况下,curl 将响应体输出到标准输出 (stdout)。您可以将其重定向到文件。

4.1 将输出保存到文件 (-o, --output)

-o <file>--output <file> 选项将响应体保存到指定的文件中,而不是打印到标准输出。这对于下载文件或将网页内容保存到本地非常有用。

bash
curl -o example.html https://www.example.com

这将把 https://www.example.com 的 HTML 内容保存到当前目录下的 example.html 文件中。

您可以结合 -s 使用,以避免在下载过程中看到进度条:

bash
curl -s -o example.html https://www.example.com

4.2 使用远程文件名保存 (-O, --remote-name)

-O--remote-name 选项会尝试根据远程 URL 的文件名部分或 Content-Disposition 响应头来确定本地保存的文件名。这在下载已知文件名但不想手动指定时很方便。

bash
curl -O https://example.com/path/to/data.zip

这将尝试将文件保存为 data.zip

bash
curl -O https://example.com/somefile.php?id=123 # 可能会保存为 somefile.php

4.3 丢弃响应体

如果您只关心响应头或使用 -w 选项获取的元信息,而不需要响应体,可以将响应体重定向到“空设备”:

  • Linux/macOS: curl ... -o /dev/null
  • Windows: curl ... -o NUL

“`bash

只检查状态码和下载时间,不保存或显示响应体

curl -s -w “Status: %{http_code}, Time: %{time_total}s\n” -o /dev/null https://www.example.com
“`

5. 高级格式化:使用 -w (write out)

-w <format_string>--write-out <format_string>curl 中最强大的输出格式化选项。它允许您在请求完成后,以高度自定义的格式输出关于传输的信息,如 HTTP 状态码、下载速度、总时间、文件大小等等。

-w 选项的参数是一个格式字符串,其中包含文本和以 %{variable_name} 形式表示的特殊变量。curl 会在完成传输后解析这个字符串,用实际的值替换变量,并将其输出到标准输出 (stdout)。

5.1 -w 的基本用法

bash
curl -w "HTTP Status: %{http_code}\n" https://www.example.com

这个命令会先执行请求,然后输出:

“`



… (响应体) …
HTTP Status: 200
“`

请注意,默认情况下,`-w` 的输出会跟在响应体之后。为了只输出 `-w` 的内容而不显示响应体,通常需要结合 `-s` 和 `-o /dev/null` (或 NUL)。

“`bash
curl -s -o /dev/null -w “HTTP Status: %{http_code}\n” https://www.example.com
“`

输出将只包含:

“`
HTTP Status: 200
“`

### 5.2 常用的 `-w` 变量

`-w` 提供了大量变量,以下是一些最常用和最有用的:

* `%{http_code}` 或 `%{response_code}`: HTTP 状态码(如 200, 404, 500)。
* `%{time_total}`: 整个传输过程的总时间(秒),从开始到结束,包括名称解析、连接、传输等所有阶段。
* `%{time_connect}`: 从开始到连接建立完成的时间(秒)。
* `%{time_starttransfer}`: 从开始到第一个字节数据传输完成的时间(秒)。
* `%{time_namelookup}`: 名称解析所需的时间(秒)。
* `%{time_pretransfer}`: 从开始到文件传输即将开始的时间(秒),包括名称解析、连接、SSL握手等。
* `%{time_redirect}`: 所有重定向步骤所花费的总时间(秒)。
* `%{speed_download}`: 平均下载速度(字节/秒)。
* `%{speed_upload}`: 平均上传速度(字节/秒)。
* `%{size_download}`: 下载的总字节数。
* `%{size_upload}`: 上传的总字节数。
* `%{url_effective}`: 如果发生重定向,这是最终有效请求的URL。否则是原始URL。
* `%{num_connects}`: 请求过程中建立的连接数。
* `%{num_redirects}`: 请求过程中发生的重定向次数。
* `%{remote_ip}`: 连接到的远程服务器IP地址。
* `%{remote_port}`: 连接到的远程服务器端口。
* `%{local_ip}`: 本地用于连接的IP地址。
* `%{local_port}`: 本地用于连接的端口。
* `%{errormsg}`: 如果发生错误,这是错误的详细描述。
* `%{content_type}`: 响应的 Content-Type 头字段的值。
* `%{num_of_shields_up}`: (玩笑变量,没有实际意义,只是展示可以自定义文本)

您可以在格式字符串中组合这些变量以及普通文本、空格、换行符 (`\n`)、制表符 (`\t`) 等。

### 5.3 `-w` 格式字符串示例

更复杂的例子:

“`bash
curl -s -o /dev/null -w “URL: %{url_effective}\nStatus: %{http_code}\nTotal Time: %{time_total}s\nDownload Speed: %{speed_download} B/s\nSize: %{size_download} bytes\n” https://www.example.com
“`

可能的输出:

“`
URL: https://www.example.com/
Status: 200
Total Time: 0.123456s
Download Speed: 10240 B/s
Size: 1270 bytes
“`

**使用 `-w` 从文件读取格式字符串 (`-w @`)**

如果格式字符串很长或您想重用它,可以将其保存在一个文件中,然后使用 `-w @` 来指定。

创建一个格式文件 (e.g., `curl_format.txt`):

“`
URL: %{url_effective}
Status: %{http_code}
Total Time: %{time_total}s
Speed: %{speed_download} B/s
Size: %{size_download} bytes
Content-Type: %{content_type}
Remote IP: %{remote_ip}
“`

然后使用:

“`bash
curl -s -o /dev/null -w “@curl_format.txt” https://www.example.com
“`

输出将按照文件的格式显示信息。

**`-w` 中的特殊字符和转义**

在 `-w` 格式字符串中,您可以使用标准 C 语言风格的转义序列,如 `\n` (换行)、`\r` (回车)、`\t` (制表符)。

如果您需要在格式字符串中包含百分号 `%` 或大括号 `{}`,并且它们不是变量的一部分,可能需要进行转义。通常,单个 `%` 可以通过 `%%` 来输出。对于 `{}`,只要它们不构成 `%{variable_name}` 的形式,通常可以直接使用。如果确实需要输出字面的 `%{}` 结构,并且可能被误认为变量,复杂的场景可能需要查阅文档或通过间接方式实现。

**`%{variable_name}` 中的修饰符**

一些变量(如 `%{http_code}`, `%{time_total}`)支持修饰符。例如,`%{http_code}` 可以是 `%{http_code}` (原始数值) 或 `%{http_code_str}` (带有文本描述,但这个变量不太常用,且描述不总是可用)。更常见的用法是 `%escape{…}`,用于对变量的值进行 URL 或 shell 安全的转义。

例如,如果 `%{url_effective}` 包含特殊字符,可以使用 `%escape{url_effective}` 进行转义。但对于大多数性能或状态信息,直接使用变量名即可。

### 5.4 `-w` 的使用场景

`-w` 选项非常适合以下场景:

* **性能监控:** 快速获取请求的总时间、连接时间、下载速度等指标。
* **状态检查:** 仅获取 HTTP 状态码来判断请求是否成功。
* **自动化脚本:** 提取特定信息(如最终 URL、内容类型)供脚本进一步处理。
* **简单的 API 测试:** 验证响应状态码或内容类型。

**重要提示:** `-w` 的输出总是发送到标准输出 (stdout),这与 `-v` 的调试信息(发送到 stderr)不同。这使得您可以轻松地将 `-w` 的输出通过管道传递给其他命令进行处理,或者将其重定向到文件,同时将响应体丢弃或保存到另一个地方。

## 6. 处理特定数据类型(JSON, XML 等)

`curl` 主要负责数据传输。它会按原样输出接收到的响应体。对于结构化数据(如 JSON 或 XML),`curl` 不会自带解析或美化功能。您需要将 `curl` 的输出通过管道传递给专门处理这些格式的工具。

### 6.1 处理 JSON 输出

常用的 JSON 处理工具是 `jq`。它可以解析 JSON 数据,并提供查询、过滤、转换等功能。

**获取并美化 JSON 输出:**

“`bash
curl -s https://api.example.com/data | jq .
“`

这里的 `jq .` 表示解析输入 JSON 并原样输出,通常会进行缩进和颜色高亮(如果终端支持)。

**提取 JSON 中的特定字段:**

假设 API 返回 `{ “name”: “Alice”, “age”: 30 }`,您只想获取 `name` 字段:

“`bash
curl -s https://api.example.com/data | jq -r ‘.name’
“`

`-r` 选项表示输出原始字符串值(不带引号)。

### 6.2 处理 XML 输出

常用的 XML 处理工具是 `xmllint`(libxml2 包的一部分)或 `xsltproc`。

**获取并美化 XML 输出:**

“`bash
curl -s https://www.w3schools.com/xml/note.xml | xmllint –format –
“`

`–format -` 表示从标准输入读取 XML 并格式化输出。

**提取 XML 中的特定元素:**

使用 `xpath` 功能(需要安装 `xmlstarlet` 或类似工具):

“`bash
curl -s https://www.w3schools.com/xml/note.xml | xmlstarlet sel -t -v “//body”
“`

这将提取 `` 元素的内容。

### 6.3 处理其他文本格式

对于纯文本或其他非标准格式,可以使用标准的 Unix/Linux 文本处理工具:

* `grep`: 搜索特定模式的行。
* `sed`: 文本替换或转换。
* `awk`: 更强大的文本处理,可以按列处理数据。
* `head`/`tail`: 查看文件头部或尾部。
* `cut`: 提取文本的指定列。
* `less`/`more`: 分页查看输出。

示例:

“`bash
# 获取响应体,并查找包含 “error” 的行
curl -s https://example.com/log | grep “error”

# 获取响应体,并只显示前10行
curl -s https://example.com/large_file | head -n 10
“`

将 `curl` 与这些工具结合使用,是处理和格式化各种类型响应体的强大方法。

## 7. 结合选项:构建定制化输出

实际使用中,您会经常组合使用 `curl` 的各种选项来实现特定的输出需求。以下是一些常见的组合示例:

* **只获取 HTTP 状态码,无其他输出:**
“`bash
curl -s -o /dev/null -w “%{http_code}”
“`
* **获取 HTTP 状态码和响应体,无进度条:**
“`bash
curl -s -w “\nStatus: %{http_code}\n”
# 注意:这里的 -w 输出会在响应体之后,加 \n 是为了让状态码独占一行
“`
* **获取 HTTP 状态码和响应头,无进度条和响应体:**
“`bash
curl -s -I -o /dev/null -w “Status: %{http_code}\n”
# -I 只获取头,-o /dev/null 丢弃可能意外出现的体,-w 获取状态码
“`
* **下载文件并显示总时间:**
“`bash
curl -s -O -w “\nTotal time: %{time_total}s\n”
# -O 下载到文件,-s 隐藏进度条,-w 显示时间
“`
* **调试重定向问题,显示详细过程和最终 URL:**
“`bash
curl -v 2> debug.log # 调试信息到 debug.log
curl -s -o /dev/null -w “Final URL: %{url_effective}\nRedirects: %{num_redirects}\nRedirect Time: %{time_redirect}s\n” # 提取关键信息
“`

通过灵活组合 `-s`, `-S`, `-i`, `-I`, `-v`, `-o`, `-O`, `-w` 以及管道操作符 `|`,您可以构建出满足几乎所有需求的 `curl` 输出。

## 8. 错误处理和退出码

除了格式化标准输出和标准错误信息,了解 `curl` 的退出码(Exit Code)也很重要,尤其是在脚本中。`curl` 在成功完成操作时通常会返回 `0`。如果发生错误,它会返回一个非零值,不同的值对应不同的错误类型(如无法连接、文件读写错误、协议错误等)。

您可以使用 `$?`(在 Bash 或 Zsh 中)或 `%errorlevel%`(在 Windows 命令提示符中)来获取上一个命令的退出码。

“`bash
curl -s -o /dev/null https://this.domain.does.not.exist
echo “Exit code: $?”

# 尝试一个成功的请求
curl -s -o /dev/null https://www.example.com
echo “Exit code: $?”
“`

了解 `curl` 的错误码列表(可以通过 `man curl` 查看 DESCRIPTION 部分或在线文档)有助于在脚本中进行健壮的错误处理。

此外,如前所述,`-w %{errormsg}` 变量可以在请求失败时提供更详细的错误信息字符串。

“`bash
# 结合 -w 和退出码进行错误报告
output=$(curl -s -o /dev/null -w “Status:%{http_code}\nError:%{errormsg}\n” https://this.domain.does.not.exist)
exit_code=$?

if [ $exit_code -ne 0 ]; then
echo “Curl failed with exit code $exit_code:”
echo “$output” # 输出包含状态码和错误信息
else
echo “Curl successful:”
echo “$output”
fi
“`

这种方式可以在脚本中优雅地处理成功和失败的情况,并输出有用的诊断信息。

## 9. 总结与最佳实践

掌握 `curl` 的输出格式化技巧,能够显著提高您的工作效率和脚本的可靠性。

**关键要点回顾:**

* 使用 `-s` 隐藏进度条和大部分信息,获取干净的响应体。
* 结合 `-S` 与 `-s`,以便在静默模式下仍能看到错误信息。
* 使用 `-v` 查看详细的调试信息,用于诊断问题。
* 使用 `-i` 查看响应头和响应体,`-I` 只查看响应头。
* 使用 `-o` 将输出保存到文件,`-O` 根据远程文件名保存。
* 利用 `-o /dev/null` (或 `NUL`) 丢弃响应体,只关注 `-w` 的输出或响应头。
* 充分利用 `-w` 选项,通过格式字符串和变量提取和定制输出性能指标、状态码、URL等信息。
* 将 `curl` 的输出通过管道传递给 `jq`, `xmllint`, `grep`, `awk` 等工具,对响应体进行复杂的解析和处理。
* 在脚本中检查 `curl` 的退出码 `$?` 进行错误处理,并可以使用 `-w %{errormsg}` 获取具体的错误描述。

**最佳实践建议:**

* **在自动化脚本中,几乎总是使用 `-s`。** 避免非必要输出干扰脚本逻辑。如果需要错误信息,使用 `-sS`。
* **需要性能或状态数据时,优先使用 `-w`。** 它是获取这些信息的标准和灵活方式。
* **需要调试时,使用 `-v`。** 将标准错误重定向到文件或管道,以便分析。
* **处理 JSON/XML 等结构化数据,务必配合 `jq`/`xmllint` 等专业工具。** `curl` 只负责传输,不负责格式解析和美化。
* **注意标准输出 (stdout) 和标准错误 (stderr) 的区别。** `-v` 输出到 stderr,响应体和 `-w` 输出到 stdout。利用重定向可以分别处理它们。
* **查阅 `curl` 文档 (`man curl`)。** 它是最权威、最全面的参考资料,特别是关于 `-w` 变量的完整列表和详细解释。

通过本文的介绍,希望您能更自如地控制 `curl` 的输出,让这个强大的工具更好地服务于您的工作。不断实践和探索不同的选项组合,您将发现 `curl` 在数据获取和网络调试方面的巨大潜力。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部