curl -w (--write-out): print the HTTP status code and other variables
- tool
- curl
- command
- curl
- flag
- -w, --write-out <format>
- default
- none (nothing is printed after the transfer)
curl -s -o /dev/null -w '%{http_code}\n' URL prints only the HTTP status code of the response. -w (--write-out) takes a format string with %{variable} placeholders and prints it after the transfer finishes, to standard output by default. It works whether or not the request succeeded, does not change curl's exit code, and is the standard way to get status codes, timings, the final URL after redirects or a response header into a shell variable.
Common variables
A local server answers /new with JSON and redirects /old to /new:
node -e 'require("http").createServer((q, r) => { if (q.url === "/old") { r.statusCode = 301; r.setHeader("Location", "/new"); return r.end(); } r.setHeader("Content-Type", "application/json"); r.end("{\"ok\":true}\n"); }).listen(5345, "127.0.0.1"); setTimeout(() => process.exit(0), 4000)' &
sleep 1
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:5345/new
curl -s -o /dev/null -w 'code=%{http_code} type=%{content_type} bytes=%{size_download}\n' http://127.0.0.1:5345/new
curl -s -o /dev/null -w 'header: %header{content-type}\n' http://127.0.0.1:5345/new
curl -s -o /dev/null -w '%{http_code} -> %{redirect_url}\n' http://127.0.0.1:5345/old
curl -sL -o /dev/null -w '%{http_code} after %{num_redirects} redirect: %{url_effective}\n' http://127.0.0.1:5345/old
curl -s -w '\n[%{http_code}]\n' http://127.0.0.1:5345/new
waitOutput
200
code=200 type=application/json bytes=12
header: application/json
301 -> http://127.0.0.1:5345/new
200 after 1 redirect: http://127.0.0.1:5345/new
{"ok":true}
[200]Without -o, the format is printed right after the body, so a leading \n keeps it on its own line. Without -L, %{redirect_url} shows where a redirect would go; with -L, %{url_effective} shows where curl ended up.
| Variable | Prints |
|---|---|
| %{http_code} | Status code of the last response; 000 when no response arrived |
| %{content_type} | The Content-Type of the response |
| %{size_download} | Bytes of body downloaded |
| %{time_total} | Total time in seconds; also time_namelookup, time_connect, time_starttransfer |
| %{url_effective} | The URL fetched last, after any redirects followed with -L |
| %{redirect_url} | The Location a redirect points to, when -L is not used |
| %{num_redirects} | Number of redirects followed |
| %header{name} | A response header value (curl 7.84.0 and later) |
| %{exitcode} %{errormsg} | curl exit code and error text (curl 7.75.0 and later) |
| %{json} | Every variable as one JSON object (curl 7.70.0 and later) |
| %{num_retries} | Retries done with --retry (curl 8.9.0 and later) |
| %{stderr} / %output{file} | Send the rest of the output to stderr or to a file (output since 8.3.0) |
Use %% for a literal percent sign and \n, \t, \r for control characters. -w @file reads the format from a file, -w @- from standard input.
When the request fails
curl -s -o /dev/null -w '%{http_code} exit=%{exitcode} %{onerror}failed: %{errormsg}\n' http://127.0.0.1:5349/ | sed -E 's/after [0-9]+ ms/after N ms/'
echo "curl exit: ${PIPESTATUS[0]}"Output
000 exit=7 failed: Failed to connect to 127.0.0.1:5349 after N ms: Could not connect to server curl exit: 7
Nothing listens on that port, so there is no status (000) and %{onerror} lets the rest of the format appear only because the transfer failed. The exit code is curl's own (7, see curl exit codes); -w never changes it.
In scripts
code=$(curl -s -o response.json -w '%{http_code}' https://api.example.org/items)
case "$code" in
2??) echo "ok" ;;
000) echo "no response" ;;
*) echo "HTTP $code"; cat response.json ;;
esacPair -w with -f (see curl -f) only when you want a non-zero exit as well: with -f and -o, a failed request writes no file, but %{http_code} still reports the status.
FAQ
Why does curl -w '%{http_code}' print 000?
No HTTP response was received: the connection failed, timed out or the host did not resolve. Check curl's exit code, or add %{exitcode} and %{errormsg} to the format.
How do I get the body and the status code in one call?
Write the body to a file with -o and print the status with -w, as in code=$(curl -s -o body.json -w '%{http_code}' URL). Appending '\n%{http_code}' to the body also works but makes parsing harder.
Why does %{http_code} not work in a Windows batch file?
cmd.exe expands % signs. In a .bat or .cmd file double every %, as in -w %%{http_code}. PowerShell and Git Bash need no change.