1382

I'm using curl at the command line on Linux to issue HTTP requests. The response bodies are printed to standard out, which is fine, but I can't see from the man page how to get curl to print the HTTP status code from the response (404, 403 etc). Is this possible?

kdt
  • 14,539
  • 5
  • 22
  • 13
  • As for me, I can see from the manual how to get the HTTP status code, but the option -w does not work. I have reported the bug to Apple. – Nicolas Barbulesco May 04 '15 at 17:51
  • 71
    The `-i` flag, as in `curl -i https://www.example.com/`, is probably what you want, as per https://superuser.com/a/514798/190188 – caw Mar 13 '17 at 03:10
  • Why not just something like `curl -IL http://www.example.com | grep "^HTTP\/"` ? – St3an Feb 18 '19 at 07:46
  • 11
    Not to future self: the answer you want is probably Cyril David's (currently in 4th position) – WhiteHotLoveTiger Jun 17 '19 at 18:08

19 Answers19

1401

A more specific way to print out just the HTTP status code is something along the lines of:

curl -s -o /dev/null -w "%{http_code}" http://www.example.org/

A lot easier to work with in scripts, as it doesn't require any parsing :-)

The parameter -I might be added to improve response load performance. This will change the call to a HEAD call which will fetch response overhead only, without the body.

Note: %{http_code} returns on first line of HTTP payload (available variables for the -w option on the curl documentation page)

i.e.:

curl -s -o /dev/null -I -w "%{http_code}" http://www.example.org/
Nate Anderson
  • 315
  • 3
  • 10
pvandenberk
  • 14,121
  • 2
  • 13
  • 3
  • 81
    -w "%{http_code}" is the bit that prints the status code. You can add a newline or two in there to separate the code from the body (-w "\n\n%{http_code}\n") – Jeffrey Martinez Jan 11 '14 at 08:33
  • 17
    Wow, this `/dev/null` thing even works in the Windows version of curl that I'm using. – Uwe Keim Jan 30 '15 at 06:53
  • 3
    I believe this downloads the entire file even though it all goes to /dev/null, so not ideal for checking the status code for huge files. `httping -c 1 -s -G -m` issues a GET and doesn't download the whole file, although I realise this question is specifically about curl. – RomanSt Dec 13 '15 at 23:59
  • @romkyns, you're correct: the first variant in my answer downloads the entire file and "saves" it to `/dev/null`, but the second variant - ie. the one using the `-I` option for `curl` - doesn't. However, care must be taken, as you're not really testing the same action: one does an HTTP `GET` request, whilst the other makes a `HEAD` request... some webservers/websites will respond with a different status code, even if the requested URL is exactly the same! – pvandenberk Jun 17 '16 at 15:56
  • 81
    FYI: `-s` = Don't show download progress, `-o /dev/null` = don't display the body, `-w "%{http_code}"` = Write http response code to stdout after exit. – Ajedi32 Jul 19 '16 at 16:59
  • ...and `-I` = *Show document info only* – Madbreaks Oct 13 '16 at 04:37
  • 3
    Are the quotes around the "%{http_code}" required ? – Hakan Baba Mar 13 '18 at 18:52
  • I had to add '-LI' param just before the URL to be able to correctly get the last status after a redirects rather than the '302' (based on @mahatmanich answer): curl -s -o /dev/null -w "%{http_code}" -LI http://www.example.org/ – Maksym Mar 16 '18 at 14:17
  • As Maksym noticed you will need to add `-L` in order to follow redirects, otherwise your status code will simply be 302 every time you encounter a page that has moved with a 301 or 302. – dragon788 Oct 05 '18 at 16:38
  • @HakanBaba - The quotes are optional, but if you want to include newline or other escaped characters you'll need quotes. – Surreal Dreams May 01 '19 at 16:00
  • for windows, use -o Nul rather than /dev/null – Praveen Tiwari Jun 26 '19 at 01:37
  • @Ajedi32 I’m pretty sure no command can write anything to stdout _after_ exit… ;-) – Raphael Schweikert Sep 10 '19 at 13:56
  • 1
    The flag `-w` is shorthand for `--write-out ` which is described as "display information on `stdout` after a completed transfer" I wish there was a `--write-err` to do the same thing, but on `stderr` so you could collect it separately. Any suggestions? – Bruno Bronosky Oct 08 '19 at 00:31
  • 1
    I used this way massive and end up with errors: error: open /dev/null: too many open files – iWizard Apr 10 '20 at 14:06
  • This should really be the accepted answer, as it works for all kinds of http requests. – RCross Sep 09 '20 at 10:31
  • 1
    This worked well and should be the accepted answer. Thank you. – DribblzAroundU82 Dec 07 '20 at 17:51
  • 2
    @BrunoBronosky Recent versions of curl can write to `stderr`. From the man page under `-w`: "`stderr` From this point on, the `-w`, `--write-out` output will be written to standard error. (Added in 7.63.0)". So you can use `-w "%{stderr}%{http_code}"` to write the status code to `stderr`. – Dario Seidl Aug 12 '21 at 09:32
  • FastAPI was giving me 405 (Method not allowed) with the `-I` option, but this works for me. – xinthose Aug 22 '22 at 15:27
  • Since I have a `.curlrc` file which instructs curl to always print request and response headers I had to add `-q` as the first option in order to only get the return code. – RobertB Sep 09 '22 at 06:33
  • [`-S`](https://man.archlinux.org/man/core/curl/curl.1.en#S,) might be in order here. – x-yuri Sep 20 '22 at 14:58
  • Just a note (from my mistakes): - the [`-w` option](https://curl.se/docs/manpage.html#-w) uses `%` to get variables; `%{http_code}` (not the `${http_code}`; that's [substitution](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Command-Substitution))! - when redirecting curl output using [`-o /dev/null`](https://curl.se/docs/manpage.html#-o), be careful **not** to redirect using [the `>`](https://www.gnu.org/software/bash/manual/html_node/Redirections.html) , this will hide the `-w` information, as *everything* is sent to `/dev/null` ; this is **wrong**: `-o > /dev/null` – Nate Anderson Jan 28 '23 at 17:52
903

This should work for you if the web server is able to respond to HEAD requests (this will not perform a GET request):

curl -I http://www.example.org

As an addition, to let cURL follow redirects (3xx statuses) add -L.

Wouter
  • 139
  • 1
  • 8
pberlijn
  • 9,600
  • 1
  • 15
  • 8
  • 221
    NB: `curl -I` does a HEAD HTTP request, which can be problematic for testing the HTTP status code for some web application servers and services – Jay Taylor Sep 06 '12 at 17:32
  • 31
    And to get just the status number, pipe it to `head -n 1|cut -d$' ' -f2` – Benubird Jul 17 '13 at 11:33
  • 51
    Don't forget to redirect curl's stderr: `curl -I http://www.example.org 2>/dev/null | head -n 1 | cut -d$' ' -f2`. Add -L to curl if you need the final status after redirects. – Aaron Blenkush Jul 24 '14 at 21:16
  • 1
    Following the redirect after only doing a HEAD request may cause interesting behavior, depending on how the app is programmed. – Scott McIntyre Sep 21 '15 at 21:16
  • 62
    `curl -I -X GET` will send a GET request, but give the same output. – jiggy Nov 30 '15 at 19:20
  • Here are two working examples, for GET and HEAD -- http://superuser.com/a/1092635/3004 – sorin Jun 23 '16 at 10:38
  • 4
    Forwarding stderr to /dev/null is not neccessary if you only want to suppress the progress bar - use `-s` switch for that. – galva Dec 12 '16 at 09:39
  • 1
    Not useful for testing services that return status codes for other methods than GET. Like, REST services. – Keith Tyler Mar 24 '17 at 22:33
  • 1
    This command shows only some info. I can't see my response. "-i" may be better. – emeraldhieu Dec 13 '17 at 04:12
  • The right way to extract the status number is using `-w` as in `curl -so /dev/null -w 'URL: %{url_effective} at ServerIP: %{remote_ip} and Response: %{response_code}\n' google.com` – Mohamed Apr 29 '20 at 13:43
  • You need to use this solution (-I) if you want to check that a URL is redirecting somewhere else. Without it, you won't get any output. – Juan Alonso Aug 11 '22 at 09:07
  • why this answer was accepted? the -I switch not only interferes with the header sent and method, but it also compromises the ability to receive the response. there is no objective justification to change the header just to see that status code which is received anyway – nir Feb 28 '23 at 10:00
  • can also use `--head` for the more verbose version of `-I` that does the same thing, but might read more inuitively – KyleMit Jun 29 '23 at 16:12
477

You can print the status code, in addition to all the headers by doing the following:

curl -i http://example.org

The good thing about -i is that it works with -X POST as well.

Cyril David
  • 4,787
  • 1
  • 12
  • 2
  • 80
    Much better than the accepted answer (which does a HEAD request). – neu242 Oct 02 '14 at 10:05
  • 18
    Maybe obvious, but `-i` does work with **any** HTTP method, not just `GET` and `POST`... :) – mac Oct 20 '14 at 10:35
  • 7
    the best answer as it makes curl output both headers and body, making it suitable for most of the tasks when used in a script – Display Name Aug 31 '15 at 19:52
  • 12
    This is the best answer, and can be used in conjunction with `-s` (don't show progress meter or error messages) and `-S`(do show error messages after all) – Jonathan Hartley Feb 23 '17 at 19:10
  • 5
    Sorry if one wants only the HTTP status code this answer is not doing that. pvandenberk's answer that sends the output to /dev/null` does output only the three digit HTTP code by then requesting only the HTTP code in the format output. – frederickjh Feb 20 '21 at 14:20
  • 1
    If you just want the line with the status code on (e.g. `HTTP/1.1 204 No Content`), you can do `curl -i http://example.org | head -n 1` – Sam Jul 21 '21 at 14:57
  • I wanted to upvote this post, but it currently has 404 upvotes. That's just too pretty to ruin it ;) – Dakkaron Aug 16 '22 at 15:21
286

If you want to see the header as well as the result you can use the verbose option:

curl -v http://www.example.org
curl --verbose http://www.example.org

The status will appear in the header. E.g.

< Date: Tue, 04 Nov 2014 19:12:59 GMT
< Content-Type: application/json; charset=utf-8
< Status: 422 Unprocessable Entity
Dennis
  • 452
  • 5
  • 14
Enrico Susatyo
  • 3,516
  • 2
  • 19
  • 20
94

If you want to capture the HTTP status code in a variable, but still redirect the content to STDOUT, you must create two STDOUTs. You can do so with process substitution >() and command substitution $().

First, create a file descriptor 3 for your current process' STDOUT with exec 3>&1.

Then, use curl's -o option to redirect the response content to a temporary fifo using command substitution, and then within that command substitution, redirect output back to your current process STDOUT file descriptor 3 with -o >(cat >&3).

Putting it all together in bash 3.2.57(1)-release (standard for macOS):

# creates a new file descriptor 3 that redirects to 1 (STDOUT)
exec 3>&1 
# Run curl in a separate command, capturing output of -w "%{http_code}" into HTTP_STATUS
# and sending the content to this command's STDOUT with -o >(cat >&3)
HTTP_STATUS=$(curl -w "%{http_code}" -o >(cat >&3) 'http://example.com')

Note that this doesn't work in /bin/sh as SamK noted in the comments below.

Heath Borders
  • 1,210
  • 9
  • 11
  • 7
    That's serious slickery...and I like it! – spyle Jan 30 '15 at 21:14
  • 4
    Now how, in turn, can I redirect the output to another variable? – Roger Filmyer Mar 12 '15 at 01:46
  • 1
    The output is in `STDOUT`, so you should be able to redirect output from the command to anywhere you like just like a regular command. I haven't tested this though. – Heath Borders Jul 21 '15 at 03:10
  • 2
    Does not work with /bin/sh. – SamK Oct 11 '18 at 14:47
  • 1
    good answer, you can also redirect to a real file and cat it later if you want portability of shells – akostadinov Feb 08 '19 at 09:40
  • 1
    Is it necessary to close the file descriptor (`exec 3>&-`) after curl has finished? – martsraits May 31 '19 at 07:01
  • Good, bug fails in cygwin, Warning: Failed to create the file /dev/fd/63: No such file or directory. Use -o curl_res.txt – Tuntable Dec 01 '19 at 06:15
  • If you want it in a variable, but don't want the whole response body to STDOUT, you can do this. HTTP_STATUS=$(curl -s -w "%{http_code}" -o /dev/null 'https://example.org') – TMB Jan 04 '22 at 22:52
  • Once the output is redirected to &3 it's unbuffered and gone so you can't redirect it further. Try this to get both. By sending the output back to stdout (&1) using process substitution, you can reorder things so the response code is followed by the output. This makes it easy to read the status and body into variables because read gobbles up everything after the status line and stuffs it into the "body" variable. ```IFS=$'\n' read -r -d '' http_status body < <(curl -s -w "%{http_code}\n" -o >(IFS= read -r -d '' -u0 stdin; printf "%s" "$stdin") $URL)``` – Bruce Aug 24 '23 at 21:57
57

Redefine curl output:

curl -sw '%{http_code}' http://example.org

Can be used with any request type.

  • -k (--insecure) is overriding -s (silent). – Ravichandra Jul 10 '18 at 11:33
  • This is the most straightforward answer -- no odd workarounds with file descriptors, hacky processing of human-readable text with `sed`, extra unwanted text output… – ijoseph Jul 07 '22 at 04:12
52

Status code ONLY

[0]$ curl -LI http://www.example.org -o /dev/null -w '%{http_code}\n' -s
[0]$ 200

All credit to this GIST

mahatmanich
  • 645
  • 5
  • 7
  • 2
    This one works like a charm, specially when using curl between Docker containers. I use it like this in PHP: `exec("curl -LI "my service name"/"the file I'm looking the HTTP code for" -o /dev/null -w '%{http_code}\n' -s")` (e.g.: `exec("curl -LI static/someimage.jpg -o [...]` where "static" is the service name defined in Docker Compose). Thanks! – Jimmy Adaro Aug 19 '21 at 20:28
  • I would get rid of the -I so it does a normal GET instead of a HEAD request. – PolyTekPatrick Mar 09 '23 at 18:32
21

This is a painful curl --fail limitation. From man curl :

-f, --fail (HTTP) Fail silently (no output at all) on server errors

But there is no way to get both the non-zero return code AND the response body in stdout.

Based on pvandenberk's answer and this other very useful trick learned on SO, here is a workaround :

curl_with_error_code () {
    _curl_with_error_code "$@" | sed '$d'
}
_curl_with_error_code () {
    local curl_error_code http_code
    exec 17>&1
    http_code=$(curl --write-out '\n%{http_code}\n' "$@" | tee /dev/fd/17 | tail -n 1)
    curl_error_code=$?
    exec 17>&-
    if [ $curl_error_code -ne 0 ]; then
        return $curl_error_code
    fi
    if [ $http_code -ge 400 ] && [ $http_code -lt 600 ]; then
        echo "HTTP $http_code" >&2
        return 127
    fi
}

This function behaves exactly as curl, but will return 127 (a return code non-used by curl) in case of a HTTP code in the range [400, 600[.

Lucas Cimon
  • 482
  • 4
  • 11
  • 3
    Agreed, not being able to see the error output is a painful limitation of the otherwise very handy --fail. How can you diagnose a REST api failure without seeing the error output? It's so unfortunate that the curl maintainer bagder stubbornly insists on not providing a --fail-but-show-error. https://github.com/curl/curl/issues/1978 – jamshid May 13 '18 at 23:33
  • As stated in documentation, it doesn't work for 401 and 407 HTTP code :( – Logan Mzz Aug 29 '19 at 08:47
  • 2
    Thanks to a colleague, I discovered `--fail --show-error` – Lucas Cimon Apr 28 '20 at 13:11
17

This will send a request to url, get only the first line of the response, split it on blocks and select the second one.

It contains the response code

curl -I http://example.org 2>/dev/null | head -n 1 | cut -d$' ' -f2
OneCricketeer
  • 218
  • 1
  • 11
  • 1
    Can you explain what this code does and how it addresses the problem given by the OP? Unexplained code can appear untrusted and dangerous to users. – bwDraco Jul 16 '15 at 01:58
  • 2
    Sure, we send a request to url, get only the first line of the response, split it on blocks and select the second one. It contains the response code that OP is looking for. – Filip Spiridonov Jul 20 '15 at 22:01
15

For a POST request, the following worked:

curl -w 'RESP_CODE:%{response_code}' -s -X POST --data '{"asda":"asd"}' http://example.com --header "Content-Type:application/json"|grep -o  'RESP_CODE:[1-4][0-9][0-9]'
zafar142003
  • 251
  • 2
  • 4
7

Use the following cURL command and pipe it to grep like so:

$ curl -I -s -L http://example.com/v3/get_list | grep "HTTP/1.1"

Here's what each flag does:

  • -I: Show only response headers
  • -s: Silent - Don't show progress bar
  • -L: Follow Location: headers

Here is a link to HTTP status codes.

Run from the command line. This curl runs in silent mode, follows any redirects, get the HTTP headers. grep will print the HTTP status code to standard output.

Cas
  • 1,944
  • 2
  • 19
  • 42
Savitoj Singh
  • 181
  • 1
  • 3
7

An example of how to use the response codes. I use this to re-download Geolite databases only if they have changed (-z) & also following redirects (-L):

url=http://example.com/file.gz
file=$(basename $url)

response=$(curl -L -s -o $file -z $file $url -w "%{http_code}")

case "$response" in
        200) do_something ;;
        301) do_something ;;
        304) printf "Received: HTTP $response (file unchanged) ==> $url\n" ;;
        404) printf "Received: HTTP $response (file not found) ==> $url\n" ;;
          *) printf "Received: HTTP $response ==> $url\n" ;;
esac
Stuart Cardall
  • 316
  • 2
  • 7
6

Here is some curl command that is using GET and that returns the HTTP code.

curl -so /dev/null -w '%{response_code}' http://www.example.org

Please remember that the approach below is using HEAD, which is faster but it may not work well with some web less compliant HTTP servers.

 curl -I http://www.example.org
sorin
  • 11,660
  • 20
  • 63
  • 73
6
curl -so -i /dev/null -w "%{http_code}"  http://www.any_example.com

This will return the following information:

  1. response data, if any data is returned by API like error
  2. status code
srana
  • 61
  • 1
  • 2
5

Split output content to stdout and HTTP status code to stderr:

curl http://www.example.org -o >(cat >&1) -w "%{http_code}\n" 1>&2

If only HTTP status code is desired to stderr, --silent can be used:

curl --silent http://www.example.org -o >(cat >&1) -w "%{http_code}\n" 1>&2

The desired stream can then be picked by redirecting unwanted one to /dev/null:

$ (curl --silent http://www.example.org -o >(cat >&1) -w "%{http_code}" 1>&2) 1>/dev/null
200
$ (curl --silent http://www.example.org -o >(cat >&1) -w "%{http_code}" 1>&2) 2>/dev/null
<!doctype html>
...

Note that for the second redirection to behave as desired, we need to run the curl command in subshell.

Jaakko
  • 320
  • 3
  • 12
  • 1
    Requires `bash` for process substitution. – Jaakko Jun 04 '19 at 08:16
  • @Bruno, I changed the example from https://superuser.com/revisions/1444693/2, as I think the `/tmp/out` `/tmp/err` files can cause unexpected results if run parallel. – Jaakko Oct 08 '19 at 08:13
3

The OP wants to know the status code. Often when downloading a file you also want to get a feel of it's size so I'm using curl first to show status code and size of file and then shut off verbose and direct file to the place and name I want:

curl -R -s -S -w  "\nhttp: %{http_code} %{size_download}\n" -o /Users/myfiles/the_local_name.html http://archive.onweb.com/the_online_name.html

Then I wait for the finishing of curl

wait ${!}

before I run the next command. The above when used in a script of many commands like above gives a nice response like:

http: 200 42824

http: 200 34728

http: 200 35452

Please note that -o in curl needs to be followed by the full path of the file + name of file. This allows you thusly to save files in a sensible name structure when you d/l them with curl. Also note that -s and -S used together silence the output but does show errors. Note also that -R tries to set the file timestamp to that of the web file.

My answer is based on what @pvandenberk originally suggested, but in addition it actually saves the file somewhere, instead of merely directing to /dev/null.

sakumatto
  • 31
  • 2
-1
$ curl -kv https://www.example.org 2>&1 | grep -i 'HTTP/1.1 ' | awk '{print $3}'| sed -e 's/^[ \t]*//'
  • 2>&1: error is stored in output for parsing
  • grep: filter the response code line from output
  • awk: filters out the response code from response code line
  • sed: removes any leading white spaces
-1

There is another way by using Powershell command which is alias to curl.exe Just type the following:

(Invoke-WebRequest -Uri https://your.website).StatusCode

-1

In Windows PowerShell:

curl https:\\www.example.org -Method HEAD

It's really just an alias for Invoke-WebRequest though.

Kebman
  • 515
  • 2
  • 5
  • 13