curl and wget Basics: HTTP Communication from the Command Line
What You'll Learn
- The role difference between
curlandwgetso you stop guessing which to use - Core commands for downloading files, checking headers, and calling APIs
- Why beginners hit "nothing was saved," "redirects don't work," and "garbled characters" — and how to fix each
- Copy-paste templates for inspecting HTTP status codes and posting JSON
Quick Summary
- One-shot file download →
wget URL - Hit an API, inspect headers, or POST →
curl URL - Want to follow redirects →
curl -L URL - Download was interrupted →
wget -c URL
Environment
- OS: Ubuntu / typical Linux
curlis usually preinstalled. Installwgetviasudo apt install wget- We focus on HTTP/HTTPS (curl also supports ftp, sftp, smtp, etc.)
1. curl vs wget: Different Roles
At a glance
| Aspect | curl | wget |
|---|---|---|
| Default behavior | Prints to stdout | Saves as a file |
| HTTP methods | GET/POST/PUT/DELETE/... | Mostly GET |
| Follow redirects | Need -L flag |
Automatic |
| Recursive download | Weak | Strong (-r) |
| Resume | -C - |
-c |
| Best for | APIs, debugging, POST | Mirroring sites, large DL |
Rule of thumb: APIs, headers, or POST involved → curl. Just grabbing a file → wget.
2. curl Basics: Print Before You Save
2-1. Hit a URL and Print the Response
$ curl https://example.com
<!doctype html>
<html>
<head>
<title>Example Domain</title>
...
-o (specify name) or -O (use the URL's filename).2-2. Save With a Custom Name: -o
$ curl -o page.html https://example.com
-o stands for output. Lowercase o takes a filename as its argument.
2-3. Save Using the URL's Filename: -O
$ curl -O https://example.com/sample.tar.gz
Uppercase O saves using the URL's trailing filename (sample.tar.gz here).
Mixing up -o and -O ends in tears
-Orequires the URL to end with a real filenamecurl -O https://example.com/(trailing slash) fails — no filename to use- When in doubt, use
-o nameand be explicit
2-4. Show Download Progress
$ curl -O --progress-bar https://example.com/big.iso
--progress-bar gives a clean progress bar — handy for long transfers.
3. The #1 Beginner Trap: Redirects and -L
https://github.com/torvalds/linux and the response looks wrong...-L explicitly to make it follow redirects.3-1. Follow Redirects With -L
# BAD: only the redirect placeholder is returned $ curl https://github.com/torvalds/linux # GOOD: fetch the final destination $ curl -L https://github.com/torvalds/linux
-L stands for Location (the HTTP Location header).
Memorize the pattern
- When hitting external sites with curl, always add
-Lto avoid surprises - File downloads often require
-Ltoo (GitHub Releases, S3 redirects, etc.)
# Standard safe pattern $ curl -LO https://github.com/some/repo/releases/download/v1.0/binary.tar.gz
4. Inspect Headers Only With -I
Want to check "is this link alive?" or "where does this redirect to?" without downloading the body? Use -I.
$ curl -I https://example.com
HTTP/2 200 content-type: text/html; charset=UTF-8 content-length: 1256 date: Sun, 26 May 2026 09:00:00 GMT server: ECS
HTTP/2 200 means "success," right?HTTP status cheat sheet
| Code | Meaning | Examples |
|---|---|---|
2xx |
Success | 200 OK, 204 No Content |
3xx |
Redirect | 301 (permanent), 302 (temp) |
4xx |
Client-side error | 404 (not found), 401/403 |
5xx |
Server-side error | 500 (bug), 503 (overload) |
4-1. Trace Where a Redirect Leads
$ curl -ILs https://bit.ly/3xxxxx | grep -i location
-L follows redirects, -s silences progress, -I shows headers only. The location: lines reveal each hop.
5. POST and JSON: Talking to APIs
-X for the HTTP method, -H for headers, and -d for the body. Remember those three flags and you're done.5-1. GET With Query Parameters
$ curl "https://api.example.com/users?id=42"
Always quote URLs containing ? and & — otherwise the shell interprets & as background-execution.
5-2. POST JSON
$ curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name":"lina","role":"beginner"}'The three-flag combo
-X POST: explicit HTTP method (optional with-d, but explicit is safer)-H "Content-Type: application/json": declare "this is JSON"-d '...': the request body. Use single quotes so the inner"don't need escaping
5-3. Bearer Token Authentication
$ curl https://api.example.com/me \
-H "Authorization: Bearer YOUR_TOKEN_HERE"Keep tokens out of your shell history
# BAD: visible in `history` and `ps` $ curl -H "Authorization: Bearer abc123..." ... # GOOD: pass via environment variable $ export API_TOKEN=abc123... $ curl -H "Authorization: Bearer $API_TOKEN" ...
Tokens visible in history or ps are an incident waiting to happen. Use env vars or ~/.netrc.
5-4. Basic Auth
$ curl -u username:password https://example.com/private
-u accepts user:pass. HTTPS only.
6. wget's Strength: Reliable Downloads
6-1. Basic: Save as a File
$ wget https://example.com/sample.tar.gz
6-2. Save With a Custom Name: -O
$ wget -O custom.tar.gz https://example.com/sample.tar.gz
-O means the opposite in curl and wget
- curl's
-O: save using the URL's filename - wget's
-O: specify the filename (equivalent to curl's-o)
Everyone who uses both gets bitten by this at least once.
6-3. Resume an Interrupted Download: -c
$ wget -c https://example.com/big.iso
-c stands for continue. If your connection dropped halfway, this picks up from where it stopped instead of restarting.
6-4. Retries and Timeouts
$ wget --tries=5 --timeout=30 https://example.com/file.zip
Survives flaky networks by retrying.
7. Recursive Download wget -r (Handle With Care)
$ wget -r -l 2 -np https://example.com/docs/
-r: recurse through links-l 2: cap depth at 2 levels-np: don't ascend to parent directories
Things you must not do
- Run
-rwith no limits → you may download the entire site - Hammer the server rapid-fire → it looks like a DoS attack
- Ignore
robots.txt→ violates terms of service
Add --wait=2 to space requests, scope the URL tightly, and check the site's policy first.
8. Encoding and Line-Ending Traps
< and weird characters. I can't read it.iconv. For structured data like JSON, pipe through a parser like jq.\r\n (CRLF). On Linux, strip them with dos2unix or tr -d '\r'.# Convert Shift_JIS to UTF-8 while saving $ curl -s https://example.com/sjis.html | iconv -f SHIFT_JIS -t UTF-8 > page.html # Strip CRLF to LF $ curl -s https://windows-server.example/data.csv | tr -d '\r' > data.csv
9. Common Beginner Pitfalls
9-1. curl URL Saved Nothing
Cause: curl prints to stdout by default. To save, use -O or -o.
$ curl -O https://example.com/file.zip $ curl -o my.zip https://example.com/file.zip
9-2. Got the Redirect Page Instead of the Content
Cause: forgot -L.
$ curl -L https://github.com/...
9-3. Query String Triggers bash: command not found
Cause: shell interpreted & as the background-execution operator.
# BAD $ curl https://api.example.com/search?q=linux&page=2 # GOOD $ curl "https://api.example.com/search?q=linux&page=2"
9-4. SSL Certificate Error
Cause: self-signed cert, expired cert, internal CA, etc.
# With verification (recommended) $ curl https://internal.example.com # Skip verification (emergencies only — never in production) $ curl -k https://internal.example.com
-k disables verification, opening the door to man-in-the-middle attacks. For production, fix the certificate chain instead.
9-5. Proxy Environment Can't Connect
$ export http_proxy=http://proxy.example.com:8080 $ export https_proxy=http://proxy.example.com:8080 $ curl https://example.com
In corporate environments, set http_proxy / https_proxy.
10. Mini Exercises
https://httpbin.org is a safe sandbox for HTTP testing — hit it freely.Exercise 1: Check the HTTP status code and content-type of https://httpbin.org/get.
Show hint
There's a flag that fetches only headers.
Show answer
$ curl -I https://httpbin.org/get
HTTP/2 200 date: ... content-type: application/json ...
Exercise 2: POST the JSON {"hello":"world"} to https://httpbin.org/post.
Show hint
The -X POST / -H / -d three-flag combo.
Show answer
$ curl -X POST https://httpbin.org/post \
-H "Content-Type: application/json" \
-d '{"hello":"world"}'You'll see "json": {"hello": "world"} echoed back in the response.
Exercise 3: Follow the redirect chain at https://httpbin.org/redirect/3 and fetch the final page.
Show hint
You need the flag that follows redirects.
Show answer
$ curl -L https://httpbin.org/redirect/3
After three hops it lands on /get and returns that response.
11. Copy-Paste Templates
curl templates
# Print to screen (debug)
curl URL
# Save (using URL's filename)
curl -O URL
# Save (custom name)
curl -o name URL
# Follow redirects and save (GitHub Releases, etc.)
curl -LO URL
# Headers only
curl -I URL
# Get just the status code
curl -s -o /dev/null -w "%{http_code}\n" URL
# POST JSON
curl -X POST URL \
-H "Content-Type: application/json" \
-d '{"key":"value"}'
# Bearer token
curl URL -H "Authorization: Bearer $API_TOKEN"
# Basic auth
curl -u user:pass URL
# With progress bar
curl -O --progress-bar URLwget templates
# Basic download wget URL # Save with custom name wget -O custom.name URL # Resume an interrupted download wget -c URL # Retries and timeout wget --tries=5 --timeout=30 URL # Quiet download (minimal log) wget -q URL # Recursive (mind the manners) wget -r -l 2 -np --wait=2 https://example.com/docs/