How to detect in Bash when Curl fails downloading non-existent file?

I'm using curl to download a zip file. curl is called from a bash script:

curl --user joedoe http://1.2.3.4/files/joedoe.zip -o /tmp/downloaded.zip

I'd like to detect when the target zip file does not exist.

I tried

if ! [[ $? == 0 ]] ; then
  echo "ERROR: problem with Curl."
  exit 1
fi ;

but it seems that $? returned by curl is 0, so I am unable to detect when the zip files does not exist.

How can it be done?


Solution 1:

This is almost a duplicate of Can I make cURL fail with an exitCode different than 0 if the HTTP status code is not 200? The most upvoted answer (i.e. most upvoted when I'm writing this) advises -f. This solution will catch 4xx or 5xx HTML error codes, but not 301 Moved Permanently. In your case the HTML error code may or may not be 301.

If I were you, I would capture and analyze this code. Fortunately your curl uses -o and writes to a regular file, not to stdout; so we can use stdout for our extra task. -w is what you need:

http_code="$(curl --user joedoe -w '%{http_code}\n' -o /tmp/downloaded.zip http://1.2.3.4/files/joedoe.zip)"
exit_status="$?"

Now you have $exit_status and $http_code to analyze. Decide if you want -f and build the logic of your script accordingly. Basically you want $http_code to be 200. Even if it's 200, check anyway if $exit_status is 0. Imagine the link is good, but you cannot write to /tmp/downloaded.zip (maybe somebody put a rogue file there in the hope you will use it). This is an example case when you can get 200 from the server and still an error (non-zero $exit_status) from curl.


Even if $exit_status is 0 and $http_code is 200, you may still want to check if /tmp/downloaded.zip is a valid zip file. A basic test may be the exit status of:

[ "$(file -b --mime-type /tmp/downloaded.zip)" = application/zip ]

(if your file supports these options). A "full" test is by checking the exit status of:

unzip -t /tmp/downloaded.zip