HTTP from the Terminal: curl and wget

Reviewed & published by Brayan K

By the end of this lesson you'll make HTTP requests straight from the shell: GET and POST with curl, send headers and bodies, authenticate, read status codes, pipe responses into other tools, and download or mirror files with wget — plus a clear sense of when to reach for each tool.

Part of the free Command Line course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

What You'll Learn

1. curl Basics: GET and Saving the Response

A plain curl URL sends a GET and prints the response body to standard output. To save it instead, use -o name to choose your own filename or -O to reuse the remote filename. Add -L so curl follows redirects (301/302) to the final page rather than printing the redirect itself.

# curl makes a single HTTP request and prints the RESPONSE BODY to
# stdout by default. A plain GET is just the URL:
curl https://example.com

echo "--- save to a filename YOU choose with -o ---"
# -o (lowercase) writes the body to the file you name.
curl -o page.html https://example.com

echo "--- save using the REMOTE filename with -O ---"
# -O (uppercase) reuses the last part of the URL as the filename,
# here it writes a local file called  robots.txt
curl -O https://example.com/robots.txt

echo "--- follow redirects with -L ---"
# Many URLs answer 301/302 and point elsewhere. -L follows them
# to the final destination instead of printing the redirect.
curl -L https://example.com

2. Response Headers, Request Headers, and Silent Mode

Use -i to include the response headers (status line, Content-Type, and so on) above the body. To send your own request headers, repeat -H 'Header: value'. In scripts, add -s (silent) to hide the progress meter so only the real output is printed.

3. Sending Data: POST, -d, and JSON

-d 'key=value' sends a request body; using -d implies POST and sets Content-Type: application/x-www-form-urlencoded for you. For a JSON API, put JSON in -d and declare it with -H 'Content-Type: application/json'. Use -X to pick another method explicitly, such as PUT or DELETE.

# -d sends a request BODY. Using -d implies -X POST and sets
# Content-Type: application/x-www-form-urlencoded automatically.
curl -d "name=ada&role=admin" https://api.example.com/users

echo "--- send JSON: set the header yourself ---"
# For a JSON API, send JSON in -d and declare it with -H.
curl -X POST https://api.example.com/users \
     -H "Content-Type: application/json" \
     -d '{"name":"ada","role":"admin"}'

echo "--- other methods: -X picks the verb ---"
# -X sets the method explicitly when you need PUT, DELETE, etc.
curl -X DELETE https://api.example.com/users/42

4. Authentication: Basic Auth and Bearer Tokens

For HTTP basic auth, pass -u user:pass and curl builds the Authorization header for you. Most modern APIs use a Bearer token instead, which you send as a header: -H "Authorization: Bearer TOKEN". Either approach combines naturally with -X, -H, and -d for authenticated requests.

# HTTP basic auth: -u sends a username and password.
curl -u ada:s3cret https://api.example.com/private

echo "--- token auth: send an Authorization header ---"
# Most modern APIs use a Bearer token instead of basic auth.
curl -H "Authorization: Bearer YOUR_TOKEN_HERE" \
     https://api.example.com/me

echo "--- combine with JSON POST and silent mode ---"
curl -s -X POST https://api.example.com/orders \
     -H "Authorization: Bearer YOUR_TOKEN_HERE" \
     -H "Content-Type: application/json" \
     -d '{"item":"book","qty":2}'

5. Status Codes and Piping the Response

To print just the status code, silence curl, discard the body to /dev/null, and ask for it with the write-out option: curl -s -o /dev/null -w "%{http_code}" URL. Because curl prints the body to stdout, you can pipe it straight into tools like grep — or into a JSON parser, which is the focus of the next lesson.

# Print JUST the status code: silence everything, throw the body
# away to /dev/null, and ask for the http_code with -w.
curl -s -o /dev/null -w "%{http_code}\n" https://example.com

echo "--- pipe the body straight into other tools ---"
# Because curl prints the body to stdout, it pipes naturally.
# Here: download a page and pull out the <title> line.
curl -s https://example.com | grep -i "<title>"

echo "--- feed JSON to a parser ---"
# Pipe an API response into a JSON tool (see the next lesson on jq).
curl -s https://api.example.com/users/1 | head -c 80

6. wget: Downloading, Resuming, and Mirroring

wget is built for downloads: it saves to disk by default using the remote filename. Add -c to resume a partial download after a dropped connection. To mirror part of a site, use -r (recursive) with -np (no-parent, stay in the starting folder) and -l to limit the depth.

# wget is built for DOWNLOADING. It saves to disk by default,
# using the remote filename — no -O needed for the common case.
wget https://example.com/files/archive.tar.gz

echo "--- resume a half-finished download with -c ---"
# If the connection dropped, -c (continue) picks up where it left
# off instead of starting the whole file over.
wget -c https://example.com/files/big.iso

echo "--- mirror part of a site recursively ---"
# -r follows links to download recursively. -np (no-parent) stays
# within the starting folder, and -l sets how deep to go.
wget -r -np -l 2 https://example.com/docs/

🎯 Your Turn: fetch a page following redirects

Fill in the one blank marked ___ using the # 👉 hint so curl follows redirects and saves the page, then run it and check the Output panel matches.

# 🎯 YOUR TURN — fetch a page, following redirects, and save it.

# 1) Follow any 301/302 redirects to the final page.
curl ___ -o site.html https://example.com   # 👉 replace ___ with  -L

# 2) Confirm it worked by printing curl's exit status (0 = success).
echo "exit: $?"

# ✅ Expected output:
#    exit: 0

🎯 Your Turn: print only the status code

Make curl print just the HTTP status code by filling in the write-out variable. Fill in the blank, then run it.

# 🎯 YOUR TURN — print ONLY the HTTP status code of a URL.

# Silence output, discard the body, and ask curl to write the
# status code. Fill in the write-out variable.
curl -s -o /dev/null -w "%{___}\n" https://example.com   # 👉 replace ___ with  http_code

# ✅ Expected output (for a healthy page):
#    200

Pro Tips

Common Errors (and the fix)

📋 Quick Reference

TaskCommandNotes
Plain GETcurl URLBody printed to stdout
Save, chosen namecurl -o file.html URLYou name the file
Save, remote namecurl -O URLUses URL filename
Follow redirectscurl -L URL301/302 to final
Include resp. headerscurl -i URLHeaders then body
Send a headercurl -H 'K: v' URLRepeat for many
POST a bodycurl -d 'k=v' URL-d implies POST
Basic authcurl -u user:pass URLOr Bearer header
Status code onlycurl -s -o /dev/null -w "%{http_code}" URLPrints e.g. 200
Download a filewget URLSaves to disk
Resume downloadwget -c URLContinue partial
Mirror a folderwget -r -np -l 2 URLRecursive, no-parent

Mini-Challenge: a tiny HTTP toolkit

No blanks this time — just a brief and an outline. Combine a status-code check, a download with curl and wget, a JSON POST, and a resumed wget into a few commands that demonstrate everything from this lesson, and check your output against the hints in the comments.

# 🎯 MINI-CHALLENGE: a tiny HTTP toolkit
# Write a few commands (or a small script) that:
#
# 1. Use curl to print ONLY the status code of a URL
#    (hint: -s -o /dev/null -w "%{http_code}\n").
# 2. Download a file with curl using the REMOTE filename (-O),
#    then download the same URL with wget and compare.
# 3. POST some JSON to an API with curl: set -H Content-Type
#    to application/json and send the body with -d.
# 4. Use wget -c to resume a download you start and interrupt.
#
# Hint: pipe a page body into grep to find a line:
#   curl -s URL | grep -i "<title>"

# your commands here

🎉 Lesson Complete!

Practice quiz

What does curl print by default when you run curl https://example.com ?

  • The response body to standard output
  • Nothing unless you pass -o
  • The response saved to a file named example.com
  • Only the HTTP status code

Answer: The response body to standard output. curl writes the response body to stdout by default, which is exactly why it pipes so nicely into tools like grep or a JSON parser.

Which curl flag tells it to follow HTTP redirects such as 301 and 302?

  • -r
  • -f
  • -L
  • -R

Answer: -L. -L (location) makes curl follow redirects to the final URL. Without it curl just prints the redirect response and stops.

What is the difference between curl -o name.html URL and curl -O URL?

  • They are identical
  • -o saves to a filename you choose; -O saves using the remote filename
  • -o follows redirects; -O does not
  • -O saves to a filename you choose; -o uses the remote filename

Answer: -o saves to a filename you choose; -O saves using the remote filename. Lowercase -o lets you name the output file. Uppercase -O reuses the last path segment of the URL as the filename.

What does curl -d 'name=ada' https://api.example.com/users do?

  • Downloads the page to a file
  • Sends a GET request with a query string
  • Deletes the resource
  • Sends a POST request with that data as the body

Answer: Sends a POST request with that data as the body. Using -d sends a request body and implies POST, with Content-Type set to application/x-www-form-urlencoded unless you override it.

Which flag adds a request header in curl?

  • -H 'Content-Type: application/json'
  • -A 'Content-Type: application/json'
  • -D 'Content-Type: application/json'
  • -X 'Content-Type: application/json'

Answer: -H 'Content-Type: application/json'. -H (header) adds a single request header. Repeat -H to send several headers such as Content-Type and Authorization.

What does the -s flag do in curl?

  • Shows the response headers
  • Silences the progress meter and error messages
  • Saves the body to a file
  • Sends the request securely over TLS

Answer: Silences the progress meter and error messages. -s (silent) hides the progress meter and error text, which is handy in scripts so only the real output is printed.

Which curl flag includes the response headers in the printed output along with the body?

  • -H
  • -h
  • -v
  • -i

Answer: -i. -i (include) prints the response status line and headers before the body. -H, by contrast, sends a request header.

How do you resume an interrupted download with wget?

  • wget -O URL
  • wget -L URL
  • wget -c URL
  • wget -r URL

Answer: wget -c URL. wget -c (continue) resumes a partially downloaded file from where it stopped instead of starting over.

Which curl flag sets a username and password for HTTP basic authentication?

  • -b user:pass
  • -u user:pass
  • -p user:pass
  • -a user:pass

Answer: -u user:pass. -u user:pass sends HTTP basic auth credentials. For token APIs you instead send a header like -H 'Authorization: Bearer TOKEN'.

Which tool is built primarily for downloading files and recursively mirroring sites, saving to disk by default?

  • wget
  • grep
  • ssh
  • curl

Answer: wget. wget saves to disk by default and supports recursive mirroring with -r. curl is a flexible single-request transfer tool that prints to stdout and pipes well.

Continue this course

Frequently asked questions

curl vs wget — when should I use which?

Use curl when you need flexible single-request transfers, especially for APIs and scripting: it speaks many methods (GET, POST, PUT, DELETE), sends custom headers and bodies, and prints the response body to stdout so it pipes cleanly into tools like grep or a JSON parser. Use wget when your goal is downloading files or mirroring a site: it saves to disk by default and supports recursive download with -r and resuming with -c. Rule of thumb: curl for talking to APIs and piping, wget for grabbing files.

Why does my POST not send any data?

You probably forgot -d, or you sent the wrong Content-Type. Using -d 'key=value' both sends a body and implies POST, defaulting to Content-Type application/x-www-form-urlencoded. For a JSON API you must also add -H 'Content-Type: application/json' and put JSON in -d, otherwise the server may reject or misread the body.

What is the difference between -o and -O in curl?

Lowercase -o lets you choose the output filename, for example curl -o page.html URL. Uppercase -O reuses the last segment of the URL as the local filename, so curl -O https://example.com/robots.txt writes a file called robots.txt. Use -o when you want a specific name and -O when the remote name is fine.

How do I send an API token or log in with curl?

For HTTP basic auth pass -u user:pass, which curl encodes into an Authorization header for you. Most modern APIs use bearer tokens instead, which you send as a header: -H 'Authorization: Bearer YOUR_TOKEN'. You can combine either with -X, -H 'Content-Type: application/json', and -d to make an authenticated POST.

How do I get just the HTTP status code or follow redirects?

To follow redirects (301, 302, and friends) add -L so curl chases the Location header to the final URL. To print only the status code, run curl -s -o /dev/null -w '%{http_code}' URL: -s hides the progress meter, -o /dev/null throws the body away, and -w with %{http_code} writes just the number, which is handy in health-check scripts.