Skip to content

/commands/curl/curl-download-file

curl -O / curl -o file: download a file with curl

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
versions
curl 7.x, curl 8.x
os
linux, macos, windows

curl -O https://example.com/file.zip downloads the file and saves it in the current directory under the name from the URL (file.zip). curl -o name.zip URL saves it under a name you choose. Add -L to follow redirects, which most download links use, and -f so that an HTTP error such as 404 fails with a non-zero exit status instead of saving the error page. The usual safe form is curl -fLO URL.

Example

A small Node.js server on 127.0.0.1 stands in for a download site; it serves one file, sends a Content-Disposition file name, answers 404 for anything else, and stops when the block requests /quit:

bash
cat > server.js <<'EOF'
const s = require("http").createServer((req, res) => {
  if (req.url === "/quit") { res.end(); return process.exit(0); }
  if (req.url === "/files/report.csv") {
    res.writeHead(200, { "Content-Type": "text/csv", "Content-Disposition": 'attachment; filename="q3.csv"' });
    return res.end("id,total\n1,10\n");
  }
  res.writeHead(404, { "Content-Type": "text/plain" });
  res.end("not found\n");
});
s.listen(5140, "127.0.0.1");
setTimeout(() => process.exit(0), 20000);
EOF
node server.js &
sleep 1
U=http://127.0.0.1:5140
curl -s -O "$U/files/report.csv"
curl -s -o data.csv "$U/files/report.csv"
curl -s -OJ "$U/files/report.csv"
curl -s --create-dirs -o downloads/report.csv "$U/files/report.csv"
ls *.csv downloads
cat data.csv
curl -s -O "$U/missing.zip"; echo "without -f: exit $?, saved: $(cat missing.zip)"
curl -sf -o other.zip "$U/missing.zip"; echo "with -f: exit $?"
curl -s "$U/quit"

Output

data.csv
q3.csv
report.csv

downloads:
report.csv
id,total
1,10
without -f: exit 0, saved: not found
with -f: exit 22

-O used the last part of the URL, report.csv. -o chose the name. -J together with -O took the name from the Content-Disposition header, q3.csv. --create-dirs created downloads/. The last two commands show why -f matters: without it the 404 page is saved as missing.zip and curl exits 0; with it curl exits 22 and saves nothing.

Options

OptionEffect
-O, --remote-nameSave under the file name from the URL, in the current directory
-o FILE, --output FILESave as FILE; -o - writes to standard output
-J, --remote-header-nameWith -O, use the name from Content-Disposition (never overwrites an existing file)
-L, --locationFollow redirects
-f, --failExit 22 on HTTP 400 and above, save nothing
-C -Resume a partial download
--create-dirsCreate the directories in the -o path
--output-dir DIRSave -O downloads in DIR (curl 7.73+)
-#, --progress-barSimple progress bar instead of the progress table
-s -SSilent, but still print errors
--retry 3Retry transient failures: timeouts and HTTP 408, 429, 500, 502, 503 and 504

Pitfalls

  • URLs with query strings. With -O, https://host/get?id=7 is saved as get (curl 8.21 drops the query part); use -o to choose a proper name.
  • Unquoted URLs. &, ? and [ have meanings in the shell and in curl's URL globbing. Quote the URL, and use -g if it contains literal brackets.
  • Overwriting. -o and -O overwrite an existing file without asking. Only -J refuses to overwrite: curl 8.21 prints Warning: Failed to open the file q3.csv: File exists and exits with code 23.
  • Windows. In PowerShell 5.1 curl is an alias of Invoke-WebRequest; call curl.exe to get real curl, which ships with Windows 10 and later.

Confirm the download

Check the exit status (echo $?, 0 means success), then the file: ls -l file.zip, file file.zip, and if the site publishes a checksum, sha256sum file.zip. -w '%{http_code} %{size_download}\n' prints the status code and the number of bytes received after the transfer.

FAQ

Why did curl save an HTML page instead of my file?

The URL redirected, or the server returned an error page. Without -L curl saves the redirect response body, and without -f it saves a 404 or 403 page with exit status 0. Use curl -fLO URL, and check the saved file with file or head.

How do I resume a download that stopped?

Run the same command with -C -, as in curl -C - -O URL. curl looks at the size of the partial file and asks the server for the rest; the server must support range requests.

How do I download several files at once?

Repeat -O for each URL, curl -O URL1 -O URL2, or use -O with a URL pattern such as https://host/file[1-5].txt. curl 7.66 and later can fetch them in parallel with -Z.

Sources