curl — Transfer data over HTTP, HTTPS, FTP, and many other protocols across all 5 shells
Equivalents in every shell
curl https://example.comcurl https://example.comcurl https://example.comInvoke-WebRequest https://example.com`curl` is an alias for `Invoke-WebRequest` in Windows PowerShell 5.1 — different flags. PowerShell 7+ ships the real `curl.exe` and unaliases `curl`.
curl https://example.comReal `curl.exe` ships with Windows 10 1803+ and Windows Server 2019+. Pre-1803 systems have no native curl.
Worked examples
Download a file to disk
curl -O https://example.com/file.zipInvoke-WebRequest https://example.com/file.zip -OutFile file.zipcurl -O https://example.com/file.zipPOST JSON to an API
curl -X POST -H "Content-Type: application/json" -d '{"name":"a"}' https://api.example.com/itemsInvoke-RestMethod -Method Post -Uri https://api.example.com/items -ContentType application/json -Body '{"name":"a"}'curl -X POST -H "Content-Type: application/json" -d "{\"name\":\"a\"}" https://api.example.com/itemsFollow redirects and show response headers only
curl -LI https://example.com(Invoke-WebRequest -Method Head https://example.com -MaximumRedirection 10).Headerscurl -LI https://example.comGotchas
- Windows PowerShell 5.1 aliases `curl` → `Invoke-WebRequest`, so `curl -O url` silently fails because `-O` means something different. Use the full `Invoke-WebRequest -OutFile`, or call `curl.exe` explicitly.
- `Invoke-WebRequest` parses HTML by default (slow on big pages); use `-UseBasicParsing` on older PowerShell to skip the DOM.
- cmd built-in HTTP is non-existent — `curl` is the standard tool, available natively only on Windows 10 1803 and later.
WSL & PowerShell Core notes
Related glossary
- Exit codes
An exit code is a one-byte unsigned integer (0–255) the parent reads via `wait()`. The shell exposes it as `$?` (bash/zsh/fish) or `$LASTEXITCODE` (PowerShell, for external programs). Conventions matter.
- Streams & file descriptors
Every Unix process is born with three open files. Knowing which one you are writing to (or reading from) is the difference between a script that works and a script that silently swallows errors.
Common tasks using curl
- Check if a URL is reachable
Test whether a URL returns 2xx/3xx — useful for healthchecks, wait-for-it scripts, and CI smoke tests.
- Check SSL certificate expiry
Print the notBefore / notAfter dates of a remote site's TLS certificate (or a local .pem file).
- Download a file from a URL
Save a remote file to disk via HTTP/HTTPS, with progress and resume where supported.
- Follow HTTP redirects
Print the redirect chain (301/302/303/307/308 hops) from a starting URL to its final 2xx destination.
- Get HTTP response headers
Inspect just the response headers of a URL — useful for debugging redirects, caching, CORS, and TLS.
- Get your public IP
Discover the IPv4 (or IPv6) address that the rest of the internet sees you originating from — for opening a firewall rule, debugging "why does this geo-blocked service reject me", checking whether a VPN / proxy is actually engaged, or seeding a DDNS update.
- Look up a hostname's IP address
Resolve a hostname (e.g. example.com) to its A / AAAA record from the shell.
- Parse a URL into its scheme, host, port, path, and query
Extract individual pieces of a URL (scheme, userinfo, host, port, path, query, fragment) — for log parsing, building tooling that rewrites endpoints, splitting connection strings, or generating routing tables from a manifest.
- Parse JSON from a shell
Extract specific fields from a JSON blob (a curl response, kubectl output, log line) and pipe them into other shell tools — the everyday "grab the .token / .items[].name / .data.url" workflow that differs sharply from just pretty-printing.
- Retry a command on failure
Re-run a command until it succeeds or a retry cap is hit — useful for flaky network calls and CI race conditions.
- Run a command with a timeout
Kill a command if it has not finished within N seconds — the standard hedge against hung network calls, runaway scripts, and tests that should never block forever.
- Send an HTTP POST request
POST a JSON body (or form fields, or a file) to a URL and capture the response.
- Send raw TCP data to a port
Push arbitrary bytes (an HTTP request, a SMTP greeting, a custom protocol probe) to a remote TCP port and inspect the reply — for debugging service compatibility, capturing banners, reproducing protocol-level bugs, or scripting integrations with text-based protocols.
- Serve the current directory over HTTP
Spin up a throwaway HTTP server that exposes the current directory — for ad-hoc file sharing, local QA, and sending a static build over your LAN.
- Test a TCP connection with nc
Confirm whether you can open a TCP socket to host:port — the basic "is this thing reachable" check before debugging deeper protocol issues.
- Test if a network port is open
Check whether a remote (or local) TCP port is accepting connections — for service health checks, firewall debugging, or pre-flight validation in scripts.
- URL-encode or decode a string
Percent-encode a string for safe inclusion in a URL query, or decode an already-percent-encoded string back to its original characters — for building API query parameters, decoding `Location:` redirect headers, and inspecting OAuth callback URLs.