272

I was always assuming that when curl got an HTTP 500 response it was returning an exit code that meant failure (!= 0), but that seems to be not the case.

Is there a way I can I make cURL fail with an exitCode different than 0 if the HTTP status code is not 200? I know I can use -w "%{http_code}" but that puts it in STDOUT, not as the exit code (besides, I'm also interested in capturing the output, which I don't want to redirect to a file, but to the screen).

289

curl --fail does part of what you want:

from man curl:

-f, --fail

(HTTP) Fail silently (no output at all) on server errors. This is mostly done to better enable scripts etc to better deal with failed attempts. In normal cases when an HTTP server fails to deliver a document, it returns an HTML document stating so (which often also describes why and more). This flag will prevent curl from outputting that and return error 22.

This method is not fail-safe and there are occasions where non-successful response codes will slip through, especially when authentication is involved (response codes 401 and 407).

But it blocks output to the screen.

  • 3
    So which parts of it does it do and not do? – rogerdpack Jul 18 '16 at 4:45
  • 7
    @rogerdpack tl;dr it does return nonzero when it detects a bad response, but it wouldn't let OP capture the response – rampion Jul 18 '16 at 7:50
  • 4
    This doesn't catch HTTP 301 Move Permanently. curl still gave exit code 0. – wisbucky May 11 '18 at 22:46
  • 5
    @wisbucky 301 isn't an error, it's a redirection status code. Errors are 4xx and 5xx status codes. – M. Justin Aug 8 '18 at 20:40
  • 1
    @wisbucky to exit nonzero on HTTP error codes and handle HTTP redirects correctly use curl -f -L and see this question for details on what -L does. – Noah Sussman Apr 24 '19 at 17:49
86

If you just want to display the contents of the curled page, you can do this:

STATUSCODE=$(curl --silent --output /dev/stderr --write-out "%{http_code}" URL)

if test $STATUSCODE -ne 200; then
    # error handling
fi

This writes the page's content to STDERR while writing the HTTP status code to STDOUT, so it can be assigned to the variable STATUSCODE.

  • 3
    How about if I want to output the response on failure (non 200), but return a non 0 status code from the script? – Justin May 3 '15 at 23:08
  • 2
    @Justin: What about if [ "$statuscode" -ne 200 ]; then exit "$statuscode"; fi ? – ghoti Jun 16 '15 at 14:51
  • 4
    @ghoti: Only unsigned 8-bit exit codes are supported, so that could get a little confusing. – Dennis Jun 16 '15 at 16:53
  • 3
    Ah, right -- and codes will wrap at 8 bits, so error 404 becomes exit value 148, 500 becomes 244. Confusing indeed! :-) – ghoti Jun 17 '15 at 20:46
  • 7
    As a slight variation, this captures the code in a variable while redirecting the response to stdout, not stderr: { code=$(curl ... as above ...); } 2>&1 The trick is { ... } 2>&1 that allows redirecting, while not spawning a different shell as ( ... ) would. – Tobia May 23 '17 at 16:44
39

I was able to do it using a combination of flags:

curl --silent --show-error --fail URL

--silent hides the progress and error
--show-error shows the error message hidden by --silent
--fail returns an exit code > 0 when the request fails

  • 9
    This doesn't show server reply. I am not OP but I suspect he wanted to see any error message from the server which is returned in body. Besides an --silent --show-error --fail works the same as just -f/--fail. – waste Oct 20 '17 at 1:12
  • 1
    Actually, --fail returns exit code 22, as documented. – Quolonel Questions Nov 10 '17 at 5:03
  • 3
    @wisbucky 301 isn't an error, it's a redirection status code. Errors are 4xx and 5xx status codes. – M. Justin Aug 8 '18 at 20:40
  • 5
    To be fair to @wisbucky, the original question states "[...] if the HTTP status code is not 200". No mention of "error" anywhere prior. – ken Sep 11 '18 at 17:11
  • 2
    @M.Justin According to curl man-page: This method is not fail-safe and there are occasions where non-successful response codes will slip through, especially when authentication is involved (response codes 401 and 407). – youfu Mar 10 '19 at 9:53
0

I recently also needed something like this but I also wanted to print the output at all times. I used the http_code extraction and grep to achieve this.

  out=$(curl -H"Content-Type: application/json"  -w '\nstatus_code=%{http_code}\n' -s http://localhost:4040${uri} -d "${body}")
  code=$(echo ${out}|grep status_code|awk -F"=" '{print $2}')
  echo ${out}
  if [[ ${code} -ge 400 ]];
  then
    exit 2;
  fi;
New contributor
skipy is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
-1

Yes there is a way to do it but is far from obvious as it involves 3 curl options:

curl -s --fail --show-error https://httpbin.org/status/200 > /dev/null
curl -s --fail --show-error https://httpbin.org/status/401 > /dev/null
curl -s --fail --show-error https://httpbin.org/status/404 > /dev/null
curl -s --fail --show-error https://bleah-some-wrong-host > /dev/null

This assures that success (0) happens only when curl end-us with final 2xx return code and that stdout gets the body and that any errors would be displayed to stderr.

Please note that curl documentation may confuse you a little bit because it mentions that --fail could succeed for some 401 codes. Based on tests that is not true, at least not when used with --show-error at the same time.

So far I was unable to find any case where curl will return success when it was not a http-succeds with these options.

  • 2
    is this essentially the same answer as Ricardo Souza's? – knocte Sep 4 '19 at 16:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.