Linux curl Command
last modified October 23, 2026
The curl command in Linux transfers data to and from servers
using URLs. It supports many protocols, including HTTP, HTTPS, FTP, and SFTP,
and is the standard tool for downloading files, inspecting HTTP responses,
and testing web APIs from the command line.
curl handles custom headers, form and JSON data, file uploads,
authentication, and cookies. The examples use the
httpbin.org service, which echoes back the
details of a request, and example.com. The jq tool
is used to pick fields from the JSON responses.
Basic usage
In its simplest form, curl sends a GET request and writes the
response body to standard output.
curl https://httpbin.org/json
The JSON document returned by the server is printed on the terminal. If no
protocol is given in the URL, curl assumes HTTP.
$ curl https://httpbin.org/json
{
"slideshow": {
"author": "Yours Truly",
"date": "date of publication",
"slides": [
{
"title": "Wake up to WonderWidgets!",
"type": "all"
},
{
"items": [
"Why <em>WonderWidgets</em> are great",
"Who <em>buys</em> WonderWidgets"
],
"title": "Overview",
"type": "all"
}
],
"title": "Sample Slide Show"
}
}
Progress meter and silent mode
When the output goes to a file or a pipe, curl shows a
progress meter on standard error. The -s option disables it.
curl -o page.html https://example.com curl -s https://example.com | grep -o "<title>.*</title>" curl -s https://nonexistent.example; echo "exit: $?" curl -sS https://nonexistent.example
The meter shows the size, speed, and elapsed time of the transfer. Silent
mode also hides error messages, so a failure is visible only through the
exit status; code 6 means that the host could not be resolved. Adding
-S brings error messages back, which makes -sS a
good default for scripts.
$ curl -o page.html https://example.com
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 577 0 577 0 0 3012 0 --:--:-- --:--:-- --:--:-- 3020
$ curl -s https://example.com | grep -o "<title>.*</title>"
<title>Example Domain</title>
$ curl -s https://nonexistent.example; echo "exit: $?"
exit: 6
$ curl -sS https://nonexistent.example
curl: (6) Could not resolve host: nonexistent.example
Saving to a file
The -o option saves the response to a given file, while
-O uses the file name from the URL.
curl -s -O https://httpbin.org/robots.txt
The file robots.txt is saved in the current directory, next to
page.html from the previous example. For URLs that do not end
with a file name, use -o. Combined with -L and
-C -, curl can also follow redirects to the actual
file and resume an interrupted download.
$ curl -s -O https://httpbin.org/robots.txt $ ls -l page.html robots.txt -rw-rw-r-- 1 jano jano 577 Oct 23 10:44 page.html -rw-rw-r-- 1 jano jano 30 Oct 23 10:44 robots.txt $ cat robots.txt User-agent: * Disallow: /deny
Response headers
The -I option sends a HEAD request and prints only the response
headers.
curl -I https://example.com
The headers contain the status line, content type, caching information, and
the server software. To print the headers together with the body of a normal
request, use -i. The -v option shows the full
conversation, including the request headers and TLS details.
$ curl -I https://example.com HTTP/2 200 date: Fri, 23 Oct 2026 08:44:34 GMT content-type: text/html; charset=utf-8 server: cloudflare last-modified: Wed, 21 Oct 2026 20:09:25 GMT allow: GET, HEAD accept-ranges: bytes age: 10863 cf-cache-status: HIT cf-ray: a4ef75eb2e41c258-BTS alt-svc: h3=":443"; ma=86400
Following redirects
By default, curl does not follow redirects. The
-L option makes it follow the Location header.
curl -sI https://httpbin.org/redirect/2 curl -sL https://httpbin.org/redirect/2 | jq .url
The first request returns a 302 status with the next location.
With -L, curl follows both redirects and receives
the final response from /get.
$ curl -sI https://httpbin.org/redirect/2 HTTP/2 302 date: Fri, 23 Oct 2026 08:44:35 GMT content-type: text/html; charset=utf-8 content-length: 247 server: gunicorn/19.9.0 location: /relative-redirect/1 access-control-allow-origin: * access-control-allow-credentials: true $ curl -sL https://httpbin.org/redirect/2 | jq .url "https://httpbin.org/get"
Custom headers
The -H option adds or replaces a request header. It can be
repeated.
curl -s -H 'Accept: application/json' -H 'X-Request-Id: 42' https://httpbin.org/headers curl -s -A 'my-client/1.0' https://httpbin.org/user-agent
The server echoes the headers it received; we remove a tracing header added
by the httpbin infrastructure. The -A option is a shortcut for
setting the User-Agent header.
$ curl -s -H 'Accept: application/json' -H 'X-Request-Id: 42' https://httpbin.org/headers | jq '.headers | del(."X-Amzn-Trace-Id")'
{
"Accept": "application/json",
"Host": "httpbin.org",
"User-Agent": "curl/7.81.0"
}
$ curl -s -A 'my-client/1.0' https://httpbin.org/user-agent
{
"user-agent": "my-client/1.0"
}
Query parameters
The -G option appends the data given with -d or
--data-urlencode to the URL as a query string.
curl -s -G -d lang=en --data-urlencode 'city=New York' https://httpbin.org/get
The --data-urlencode option encodes special characters such as
spaces, which plain -d does not do. Without encoding, a value
like John Doe would produce an invalid URL.
$ curl -s -G -d lang=en --data-urlencode 'city=New York' https://httpbin.org/get | jq '{args, url}'
{
"args": {
"city": "New York",
"lang": "en"
},
"url": "https://httpbin.org/get?lang=en&city=New+York"
}
Sending POST data
The -d option sends data in the request body. It switches the
method to POST and, by default, uses the form content type.
curl -s -d 'name=John&occupation=gardener' https://httpbin.org/post
curl -s -X POST -H 'Content-Type: application/json' -d '{"name": "John", "age": 34}' https://httpbin.org/post
The first command submits form data. The second one sends a JSON document;
the Content-Type header tells the server how to parse it. The
-X POST option is redundant here but makes the intention
explicit. Since version 7.82, curl provides the
--json option, which sets the data and the JSON headers at once.
With -d @file.json, the data is read from a file.
$ curl -s -d 'name=John&occupation=gardener' https://httpbin.org/post | jq .form
{
"name": "John",
"occupation": "gardener"
}
$ curl -s -X POST -H 'Content-Type: application/json' -d '{"name": "John", "age": 34}' https://httpbin.org/post | jq .json
{
"age": 34,
"name": "John"
}
Uploading files
The -F option submits a multipart form, as a browser does for
forms with file inputs.
curl -s -F 'file=@notes.txt' -F 'note=report' https://httpbin.org/post
The @ prefix tells curl to upload the contents of
notes.txt as a file field. Fields without the prefix are sent as
regular form values.
$ echo "sample data" > notes.txt
$ curl -s -F 'file=@notes.txt' -F 'note=report' https://httpbin.org/post | jq '{files, form}'
{
"files": {
"file": "sample data\n"
},
"form": {
"note": "report"
}
}
Other HTTP methods
The -X option sets the request method, which is needed for REST
APIs.
curl -s -X PUT -d 'status=done' https://httpbin.org/put
curl -s -o /dev/null -w '%{http_code}\n' -X DELETE https://httpbin.org/delete
The first command sends a PUT request with form data. The second one sends a
DELETE request, discards the body, and prints only the status code. Do not
use -X HEAD; use -I instead.
$ curl -s -X PUT -d 'status=done' https://httpbin.org/put | jq .form
{
"status": "done"
}
$ curl -s -o /dev/null -w '%{http_code}\n' -X DELETE https://httpbin.org/delete
200
Basic authentication
The -u option sends a user name and password with HTTP basic
authentication.
curl -s -u john:secret https://httpbin.org/basic-auth/john/secret
The correct credentials are accepted, and wrong ones lead to status
401. If only the user name is given, curl prompts
for the password, which keeps it out of the shell history. Bearer tokens are
sent with a header, for example -H "Authorization: Bearer $TOKEN".
$ curl -s -u john:secret https://httpbin.org/basic-auth/john/secret
{
"authenticated": true,
"user": "john"
}
$ curl -s -o /dev/null -w '%{http_code}\n' -u john:wrong https://httpbin.org/basic-auth/john/secret
401
Cookies
The -c option saves cookies received from the server to a file,
and -b sends cookies from a file or a string.
curl -s -c cookies.txt https://httpbin.org/cookies/set/session/abc123 -o /dev/null curl -s -b cookies.txt https://httpbin.org/cookies curl -s -b 'theme=dark' https://httpbin.org/cookies
The first request stores the session cookie in a cookie jar in
the Netscape format. The second request sends it back, which is how a login
session is kept across several curl calls. The last command
sends a cookie given directly on the command line.
$ curl -s -c cookies.txt https://httpbin.org/cookies/set/session/abc123 -o /dev/null
$ grep session cookies.txt
httpbin.org FALSE / FALSE 0 session abc123
$ curl -s -b cookies.txt https://httpbin.org/cookies
{
"cookies": {
"session": "abc123"
}
}
$ curl -s -b 'theme=dark' https://httpbin.org/cookies
{
"cookies": {
"theme": "dark"
}
}
Writing out transfer details
The -w option prints information about the completed transfer
using variables.
curl -s -o /dev/null -w 'status: %{http_code}\nsize: %{size_download} bytes\ntype: %{content_type}\n' https://example.com
We discard the body and print the status code, the number of downloaded
bytes, and the content type. Other useful variables include
%{time_total} and %{url_effective}, which makes
-w handy for simple monitoring.
$ curl -s -o /dev/null -w 'status: %{http_code}\nsize: %{size_download} bytes\ntype: %{content_type}\n' https://example.com
status: 200
size: 577 bytes
type: text/html; charset=utf-8
Failing on HTTP errors
By default, curl considers any HTTP response a success, even
404 or 500. The -f option makes it
fail on HTTP errors.
curl -s https://httpbin.org/status/404; echo "exit: $?" curl -sf https://httpbin.org/status/404; echo "exit: $?" curl -sSf https://httpbin.org/status/500
Without -f, the exit status is 0; with it, curl
exits with code 22 and prints no body. Use -f in scripts so that
failed requests are detected. The --retry option repeats
requests that fail with transient errors.
$ curl -s https://httpbin.org/status/404; echo "exit: $?" exit: 0 $ curl -sf https://httpbin.org/status/404; echo "exit: $?" exit: 22 $ curl -sSf https://httpbin.org/status/500 curl: (22) The requested URL returned error: 500
Best practices for curl
- Use -sSf in scripts: Hide the progress meter, show errors, and fail on HTTP errors.
- Follow redirects: Add
-Lwhen downloading files that may be redirected. - Encode data: Use
--data-urlencodefor values with spaces or special characters. - Protect secrets: Avoid passwords on the command line;
let
curlprompt or use a.netrcfile. - Keep TLS verification: Do not use
-koutside of testing.
See also
For working with web APIs interactively, the xh
command is a friendlier alternative: it builds JSON bodies, headers, and
query parameters from short key=value items, formats the
responses, and fails on HTTP errors by default. Its --curl
option translates a request into the equivalent curl
command.
Source
In this article, we have used the curl command to download
files, inspect headers, follow redirects, send query parameters, form and
JSON data, upload files, authenticate, work with cookies, and handle errors.
Author
List all Linux tutorials.