curlは、コマンドラインからHTTPリクエストを送るためのツールです。WebページやAPIのデータを取得したり、ファイルをダウンロードしたり、POSTでデータを送信したりと、ブラウザなしでWebとやり取りできます。APIの動作確認、Webサーバーの応答チェック、スクリプトからのデータ取得など、開発の現場で毎日のように使われる定番コマンドです。
つまずきやすいのは、リダイレクト(301など)をそのままでは追わないこと(-Lが必要)と、ヘッダーの確認やPOSTの書き方です。この記事では、実際のWebサーバーにcurlでリクエストを送りながら、基本のGETからAPIのPOST送信まで、実務で使うパターンを整理します。Windows 10以降・macOS・Linuxには標準でcurlが入っているので、すぐ試せます。
- 基本は
curl URL。ファイル保存は-o 名前または-O(元の名前)です。 - リダイレクトを追うには
-L。付けないと301の応答自体が返ります。 - ヘッダーだけ見るのは
-I、ステータスコードは-w "%{http_code}"。 - ヘッダー付与は
-H、POST送信は-d(自動でPOSTになります)。 - エラー(4xx/5xx)を失敗として扱うには
-f、進捗を消すには-s。 - APIのJSON送信は
-H "Content-Type: application/json" -d '...'です。
取得したデータの絞り込みはgrep、レスポンスの加工はawk、リダイレクトの仕組みはリダイレクトとパイプもあわせて参考になります。
基本のGETとダウンロード(-o / -O)
URLを指定するだけで、そのページの内容(HTMLやJSON)が表示されます。ファイルとして保存するには-o(名前を指定)か-O(URLの元の名前で保存)を使います。
# ページ/APIの内容を取得して表示 curl https://example.com/ # -o: 名前を指定して保存 curl -o page.html https://example.com/ # -O: URL上のファイル名でそのまま保存 curl -O https://example.com/robots.txt # → robots.txt という名前で保存される # -s: 進捗メーターを消す(スクリプト向き) curl -s https://example.com/ -o /dev/null
実際のサーバーで確認したところ、curl -O https://(サイト)/robots.txtでrobots.txtというファイル名のまま保存され、中身(User-agent: *…)も正しく取得できました。-oは名前を自分で決めたいとき、-Oは元のファイル名で保存したいときに使います。デフォルトではダウンロードの進捗メーターが表示されますが、スクリプトで使うときや出力を他のコマンドへ渡すときは-s(サイレント)で消すのが定番です(実機でも-sなしでは進捗が、付けると消えることを確認しました)。
ステータスコードとヘッダー(-I / -w)
「ページが正常か(200か)」「どんなヘッダーが返るか」を確認するには、-I(ヘッダーのみ取得)や-w(書式指定で情報を出力)を使います。サーバーの死活監視やレスポンス確認の基本です。
# -I: レスポンスヘッダーだけを取得(本文は取らない)
curl -I https://example.com/
# HTTP/2 200
# server: nginx
# content-type: text/html; charset=UTF-8
# -w: ステータスコードだけを取り出す(本文は捨てる)
curl -s -o /dev/null -w "%{http_code}\n" https://example.com/
# 200
# 応答時間やサイズも取れる
curl -s -o /dev/null -w "code:%{http_code} time:%{time_total}s\n" https://example.com/
実機でも、-IでHTTP/2 200・server: nginx・content-typeなどのヘッダーが取得でき、-s -o /dev/null -w "%{http_code}"でステータスコード(200)だけを取り出せることを確認しました。この-o /dev/null(本文を捨てる)+-wの組み合わせは、Webサイトの死活監視スクリプトの定番です。%{http_code}のほか、%{time_total}(総時間)、%{size_download}(サイズ)、%{url_effective}(最終URL)などが取得できます。
【重要】リダイレクトを追う(-L)
curlで最もつまずくのがこれです。サーバーが301や302でリダイレクトを返しても、curlは既定ではそれを追いません。リダイレクト先の内容が欲しいときは-L(location追跡)を付けます。
# -L なし: リダイレクトの応答(301)がそのまま返る
curl -s -o /dev/null -w "%{http_code}\n" https://example.com/old-page/
# 301 ← 中身ではなく「移動しました」の応答
# -L あり: リダイレクト先まで追って最終ページを取得
curl -sL -o /dev/null -w "%{http_code} %{url_effective}\n" https://example.com/old-page/
# 200 https://example.com/new-page/ ← 追跡して最終URLに到達
実際のサイトで、301リダイレクトを設定したURLに対して試しました。-Lなしではcurlは301(移動の応答)を受け取ってそこで止まり、リダイレクト先の中身は取得されませんでした。一方-Lを付けると、curlがリダイレクトを追って最終ページ(200)まで到達し、%{url_effective}で最終的なURLも確認できました。「curlでページが取れない」「中身が空でヘッダーだけ返る」というときは、リダイレクトを追えていないことが多いので、まず-Lを付けてみてください。httpからhttpsへの転送や、wwwあり・なしの統一でもリダイレクトは頻繁に発生します。ファイルのダウンロード(-O)でも、配布元がリダイレクトしている場合は-Lが必要です。
ヘッダーを付ける(-H)とUser-Agent(-A)
APIでは、認証トークンやコンテンツタイプをヘッダーで送ることがよくあります。-H "名前: 値"で任意のヘッダーを追加できます。-AはUser-Agent(ブラウザ種別)専用の指定です。
# 任意のヘッダーを追加(複数可) curl -H "X-Api-Key: abc123" -H "Accept: application/json" https://api.example.com/data # 認証トークン(Bearer)を送る curl -H "Authorization: Bearer YOUR_TOKEN" https://api.example.com/me # -A: User-Agent を指定(ブラウザのふりをする等) curl -A "Mozilla/5.0" https://example.com/ # Basic認証は -u(ユーザー:パスワード) curl -u username:password https://example.com/secret
実機で-v(詳細表示)で送信内容を確認したところ、-H "X-Test: hello"で指定したヘッダーが実際にリクエストへ付与され(x-test: helloとして送信)、-A "MyAgent/1.0"もUser-Agentヘッダーとして送信されることを確認しました。APIを叩くときは-H "Authorization: Bearer トークン"で認証情報を、-H "Accept: application/json"でJSON形式の要求を送るのが定番です。ID/パスワードによるBasic認証なら-u ユーザー:パスワードが簡単です。
POST送信とAPI(-d / -X / JSON)
データを送るには-dを使います。-dを付けると自動的にPOSTメソッドになり、フォーム送信と同じ形式でデータが送られます。APIへのJSON送信は、Content-Typeヘッダーとあわせて指定します。
# フォーム形式でPOST(-d を付けると自動で POST になる)
curl -d "name=taro&age=20" https://api.example.com/users
# JSON を送る(Content-Type を明示)
curl -H "Content-Type: application/json" \
-d '{"name":"taro","age":20}' \
https://api.example.com/users
# メソッドを明示的に指定(PUT/DELETE など)
curl -X PUT -d "status=done" https://api.example.com/tasks/1
curl -X DELETE https://api.example.com/tasks/1
# 特殊文字を含む値は --data-urlencode で安全に
curl --data-urlencode "q=a b&c" https://api.example.com/search
実機で-vにより送信リクエストを確認しました。-d "name=taro&age=20"を付けると、リクエストは自動的にPOSTになり、content-type: application/x-www-form-urlencoded(フォーム形式)で本文が送られました。さらに-H "Content-Type: application/json"を加えるとcontent-type: application/jsonに切り替わり、JSONとして送信されました。-X PUTや-X DELETEでメソッドを明示的に指定できることも確認しています(-dだけならPOSTなので、GET/POST以外を使うときに-Xが必要)。&やスペースなど特殊文字を含む値は--data-urlencodeを使うと、自動でURLエンコードされて安全に送れます(実機でもスペースや&入りの値が正しくエンコードされました)。REST APIのテストは、この-d+-H+-Xの組み合わせでほぼ賄えます。
エラーの扱い(-f)とデバッグ(-v)
スクリプトで使うときは、404や500を「失敗」として検知したいことがあります。-fを付けると、HTTPエラー時にcurl自体がエラー終了します。通信の中身を追うには-v(詳細表示)が役立ちます。
# -f: 4xx/5xx のときエラー終了する(終了コードが 0 以外に) curl -sf https://example.com/notfound echo $? # 22(HTTPエラーで失敗) # スクリプトでの判定 if curl -sf -o data.json https://api.example.com/data; then echo "取得成功" else echo "取得失敗" fi # -v: リクエストとレスポンスの詳細を表示(デバッグ) curl -v https://example.com/ # > で始まる行が送信、< で始まる行が受信
実機でも、存在しないURLに-fを付けると終了コードが22(HTTPエラーで失敗)になることを確認しました。-fなしだと、404が返ってもcurl自体は「通信成功」として終了コード0を返すため、スクリプトでエラーを検知したいときは-fが必須です。ifと組み合わせて取得の成否で処理を分ける、といった使い方ができます。通信がうまくいかないときは-vで、送信ヘッダー(>)と受信ヘッダー(<)を確認すると原因を切り分けられます。
主なオプション一覧
curlでよく使うオプションをまとめます。
| オプション | 働き |
|---|---|
-o 名前 / -O |
ファイル保存(名前指定 / 元の名前) |
-L |
リダイレクトを追う |
-I / -s |
ヘッダーのみ / 進捗を消す |
-H "名前: 値" |
ヘッダーを追加 |
-d データ |
POST送信(自動でPOSTに) |
-X メソッド |
PUT/DELETE等を明示 |
-u ユーザー:パス / -f |
Basic認証 / エラー時に失敗 |
よくある失敗
-Lを付けずリダイレクトで中身が取れない
301/302はそのままでは追いません。リダイレクト先が欲しいなら-Lを付けます。
404でもスクリプトが成功扱いになる
-fを付けないとHTTPエラーでも終了コード0です。検知するには-fを使います。
JSONを送ったのにフォーム扱いされる
-H "Content-Type: application/json"を付け忘れています。明示が必要です。
特殊文字を含むデータが壊れる
スペースや&は--data-urlencodeでエンコードして送ります。
進捗表示が出力に混ざる
パイプやファイル出力では-sで進捗を消します(エラーも消したくなければ-sS)。
よくある質問
curl -O URLで、URL上のファイル名のまま保存できます。名前を指定したいときはcurl -o 名前 URLです。実機でも、-Oでrobots.txtがそのままの名前で保存されることを確認しています。配布元がリダイレクトしている場合は-Lも付けてください。-Lを付けます。curlは既定ではリダイレクト(301/302)を追わず、移動の応答をそのまま返します。実機でも、-Lなしでは301で止まり、-Lありで最終ページ(200)まで到達することを確認しています。「中身が取れない」ときは、まず-Lを疑ってください。curl -d "キー=値" URLとします。-dを付けると自動的にPOSTになり、フォーム形式で送信されます。JSONを送るときは-H "Content-Type: application/json" -d '{...}'のように、Content-Typeヘッダーを明示してください。実機でも、-dでPOSTになりContent-Typeが切り替わることを確認しています。curl -s -o /dev/null -w "%{http_code}\n" URLとします。-o /dev/nullで本文を捨て、-w "%{http_code}"でステータスコードだけを出力します。Webサイトの死活監視スクリプトの定番です。応答時間は%{time_total}でも取れます。curl -H "Authorization: Bearer YOUR_TOKEN" URLのように、-HでAuthorizationヘッダーを付けます。ID/パスワードのBasic認証ならcurl -u ユーザー:パスワード URLが簡単です。APIキーをヘッダーで送る場合も-H "X-Api-Key: ..."のように指定します。まとめ
- 基本は
curl URL、保存は-o/-O、進捗を消すなら-s。 - リダイレクトを追うには
-L。中身が取れないときの第一候補です。 - 確認系は
-I(ヘッダー)・-w "%{http_code}"(ステータス)。 - POSTは
-d(自動でPOST)、JSONは-H "Content-Type: application/json"を明示。 - スクリプトでは
-fでエラー検知、-vでデバッグします。
curlは、APIのテストからファイル取得、サーバー監視まで、Web開発に欠かせない万能ツールです。「取れないときは-L」「POSTは-d」「エラー検知は-f」——この3つを押さえれば、日常のHTTP操作でつまずくことはほとんどありません。取得したJSONはgrepや専用ツールで加工して、スクリプトに組み込んでみましょう。

