Skip to content

/flags/curl/curl-w-write-out

curl -w (--write-out): print the HTTP status code and other variables

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · curl 8.21.0 (x86_64-w64-mingw32) libcurl/8.21.0 Schannel zlib/1.3.2updated
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:

bash
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
wait

Output

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.

VariablePrints
%{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

bash
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

bash
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 ;;
esac

Pair -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.

Sources