はじめに
この記事はUdon Advent Calendar 2025 - Adventarの4日目の記事です。
1日目の記事や2日目の記事でcURLコマンドを使って何かをやった、ということを書いてきましたが、肝心のcURLコマンド本体の説明は省いてきました。
今年度は何かとこのコマンドと縁のある生活をしてきたので、ここらで一つcURLコマンドについてまとめておきたいと思います。
cURLとは?
cURLはclient URLの略で、一言で言えば「通信を様々なプロトコル、条件の下で行う」コマンドです。
このコマンドはOSSとして公開されており、自由に利用させていただくことが可能です。
上記のページのトップにも書いてありますが、以下のように様々な通信プロトコルに対応しています(この他にもあります)。
- FTP
- HTTP, HTTPS
- IMAP, IMAPS
- LDAP, LDAPS
- POP3, POP3S
- SCP
- SMTP, SMTPS
- TELNET
また、HTTPを例に取ると、以下のような通信形式に対応しています。
- GET
- POST
- PUT
- HEAD
- cookies
このコマンドを実行することにより、
- 相手に形式を指定した通信を送信する
- 返信を受け取って表示する
といったことができます。
最も基本的な例は以下のとおりです。
curl https://example.com
これはexample.comに大してHTTPS通信を行うコマンドです。これを実行すると以下のようになります。
$ curl https://example.com
<!doctype html><html lang="en"><head><title>Example Domain</title><meta name="viewport" content="width=device-width, initial-scale=1"><style>body{background:#eee;width:60vw;margin:15vh auto;font-family:system-ui,sans-serif}h1{font-size:1.5em}div{opacity:0.8}a:link,a:visited{color:#348}</style><body><div><h1>Example Domain</h1><p>This domain is for use in documentation examples without needing permission. Avoid use in operations.<p><a href="https://iana.org/domains/example">Learn more</a></div></body></html>
htmlという文言が見えると思います。HTTPは「Hyper Text Transfar Protocol」を縮めたもので、「ハイパーテキスト」つまり「HTML」を受け渡す通信なのです。それをcurlで行ったので、コマンドの結果としてサイトからのレスポンスがこういった形で返って来たわけです。
インストール
Linux
基本的に最初からインストールされていると思います。もしされていない場合は、以下のコマンドでインストールできます。
Ubuntu/Debian
sudo apt update
sudo apt install curl
CentOS/RHEL
sudo yum install curl
Windows
ややこしいことにWindowsでそのままcURLを使うと変なことになります。
> curl https://example.com
StatusCode : 200
StatusDescription : OK
Content : <!doctype html><html lang="en"><head><title>Example Domain</title><meta name="viewport" content="width=device-width,
initial-scale=1"><style>body{background:#eee;width:60vw;margin:15vh auto;font-famil...
RawContent : HTTP/1.1 200 OK
Connection: keep-alive
Alt-Svc: h3=":443"; ma=93600
Content-Length: 513
Cache-Control: max-age=86000
Content-Type: text/html
Date: Wed, 03 Dec 2025 13:29:04 GMT
ETag: "bc2473a18...
Forms : {}
Headers : {[Connection, keep-alive], [Alt-Svc, h3=":443"; ma=93600], [Content-Length, 513], [Cache-Control, max-age=86000]...}
Images : {}
InputFields : {}
Links : {@{innerHTML=Learn more; innerText=Learn more; outerHTML=<A href="https://iana.org/domains/example">Learn more</A>; o
uterText=Learn more; tagName=A; href=https://iana.org/domains/example}}
ParsedHtml : mshtml.HTMLDocumentClass
RawContentLength : 513
なにやら詳細な情報が出て来ていますが、肝心のレスポンスであるHTMLは途中で切れてしまっています。
これは、curlというコマンドがデフォルトでは「Invoke-WebRequest」のエイリアスとして割り当てられているからです。つまり上は「Invoke-WebRequest」の出力結果でありcurlの出力結果なわけです。
無理にWindowsでやる必要はないので、WSLがある人はそれを利用した方が良いでしょう。
どうしてもWindowsで使いたい人は以下の記事が参考になると思います。
Mac
brew install curl
オプション
上記のHTTP通信は最も簡単な例です。実際はここにオプションをつけ、多様な通信を実現することになります。
-o:レスポンスをファイルに保存
$ curl -o output.html https://example.com
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 513 100 513 0 0 853 0 --:--:-- --:--:-- --:--:-- 852
$ cat output.html
<!doctype html><html lang="en"><head><title>Example Domain</title><meta name="viewport" content="width=device-width, initial-scale=1"><style>body{background:#eee;width:60vw;margin:15vh auto;font-family:system-ui,sans-serif}h1{font-size:1.5em}div{opacity:0.8}a:link,a:visited{color:#348}</style><body><div><h1>Example Domain</h1><p>This domain is for use in documentation examples without needing permission. Avoid use in operations.<p><a href="https://iana.org/domains/example">Learn more</a></div></body></html>
やっていることは以下と同じ。
curl https://example.com > output.html
-s:ログの非表示
上で出ていた進行状況ログを非表示する。
$ curl -s -o output.html https://example.com
$ cat output.html
<!doctype html> ...
-v:詳細ログの表示
通信過程のログが詳細に表示される。
$ curl -v https://example.com
* Host example.com:443 was resolved.
* IPv6: 2600:1406:bc00:53::b81e:94c8, 2600:1408:ec00:36::1736:7f31, 2600:1406:5e00:6::17ce:bc1b, 2600:1406:bc00:53::b81e:94ce, 2600:1408:ec00:36::1736:7f24, 2600:1406:5e00:6::17ce:bc12
* IPv4: 23.192.228.80, 23.220.75.232, 23.220.75.245, 23.215.0.136, 23.215.0.138, 23.192.228.84
* Trying 23.192.228.80:443...
* Connected to example.com (23.192.228.80) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519 / id-ecPublicKey
* ALPN: server accepted h2
* Server certificate:
* subject: C=US; ST=California; L=Los Angeles; O=Internet Corporation for Assigned Names and Numbers; CN=*.example.com
* start date: Jan 15 00:00:00 2025 GMT
* expire date: Jan 15 23:59:59 2026 GMT
* subjectAltName: host "example.com" matched cert's "example.com"
* issuer: C=US; O=DigiCert Inc; CN=DigiCert Global G3 TLS ECC SHA384 2020 CA1
* SSL certificate verify ok.
* Certificate level 0: Public key type EC/prime256v1 (256/128 Bits/secBits), signed using ecdsa-with-SHA384
* Certificate level 1: Public key type EC/secp384r1 (384/192 Bits/secBits), signed using ecdsa-with-SHA384
* Certificate level 2: Public key type EC/secp384r1 (384/192 Bits/secBits), signed using ecdsa-with-SHA384
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://example.com/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: example.com]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.5.0]
* [HTTP/2] [1] [accept: */*]
> GET / HTTP/2
> Host: example.com
> User-Agent: curl/8.5.0
> Accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
< HTTP/2 200
< content-type: text/html
< etag: "bc2473a18e003bdb249eba5ce893033f:1760028122.592274"
< last-modified: Thu, 09 Oct 2025 16:42:02 GMT
< cache-control: max-age=86000
< date: Wed, 03 Dec 2025 14:27:23 GMT
< content-length: 513
< alt-svc: h3=":443"; ma=93600
<
<!doctype html>...
名前解決の過程などが書いてあるのがわかる。
-I:リクエストヘッダの表示
コマンド実行後、レスポンスの代わりにリクエストヘッダが表示される。
$ curl -I https://example.com
HTTP/2 200
content-type: text/html
etag: "bc2473a18e003bdb249eba5ce893033f:1760028122.592274"
last-modified: Thu, 09 Oct 2025 16:42:02 GMT
cache-control: max-age=86000
date: Wed, 03 Dec 2025 14:20:48 GMT
alt-svc: h3=":443"; ma=93600
ステータスコードなどが確認できる。
-k:SSLエラーの無視
証明書が不正などといったエラーを無視して通信を行う。
curl -k https://example.com
-X:リクエストメソッドの指定
POSTリクエストなどを行いたいときはこれを用いる。
curl -X POST https://example.com
-H:リクエストヘッダの追加
リクエストに必要なヘッダ情報(トークンとか)を追加する。
curl -X POST -H "token: aaaa1234" https://example.com
ヘッダ情報が色々付加されることで通信が特徴づけられるので大切なオプション。
-d:送信データの追加
POSTリクエストで送信するデータを追加する。データはテキストだったりJSONだったりする。JSONを送る場合はヘッダの追加が必要。
curl -X POST -d "foo=bar&hoge=fuga" https://example.com
curl -X POST -H "Content-Type: application/json" -d '{"foo": "bar", "hoge": "fuga"}' https://example.com
時には長大なデータや画像ファイルを付加することもある。以下のようにするとファイルを直接指定できる。
curl -X POST -H "Content-Type: application/json" -d @data.json http://example.com/
応用
「様々な通信を行うコマンド」というシンプルな触れ込みのため、応用例も幅広いです。
APIを叩く
1日目の記事ではQiitaにブログ記事をcURLコマンドを用いて投稿する例を示しています。
各サービスのAPIを叩く(利用する)ことも立派な通信の一つなのでcURLで行うことができます。認証情報は-Hオプション、リクエストに際して送信するデータは-dオプションを用いて付加することが多いです。
また、各サービスのAPIに用意されたドキュメントにはAPIの利用例が載っており、だいたいはその中にcURLでの例が示されています。
cURLでAPIを叩くときはこれをチェック(コピペ)し、必要な情報を入れてから実行するという流れが定番です。
APIを「叩く」、とよく言いますが、cURLを使うとコマンドを実行する=ボタンを「叩く」という操作がそのままAPIへの通信になるので、より「叩いている」気がします。
ブラウザのCopy as cURL機能
cURLによってほとんどの通信が再現できます。なので、普段ブラウザ上でWebサーバとの間で行われている通信も再現できます。
こういった通信を再現するのに便利な機能がブラウザの開発者ツールには備わっています。
ブラウザでF12キーを押すとこのようなコンソールが現れます。
今回はネットワークタブ(左から5番目)のみを説明します。
何やら棒グラフのようなものがありますが、これはページを読み込む際に実際に行われた通信を表しています。このページはHTTP通信のみらしいですね。
左クリックしてみるとこのように5つのタブが現れます。ヘッダ、プレビューなどがあり、画像の通りレスポンスタブを見てみるとHTMLの中身を見ることができます。
右クリックしてみて、「Copy」にホバーするとこのように「Copy as cURL(bash)」というものがあります。これをクリックすると以下のようなものがクリップボードに入ります。
curl 'http://example.com/' \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' \
-H 'Accept-Language: ja,en;q=0.9,en-GB;q=0.8,en-US;q=0.7' \
-H 'Cache-Control: max-age=0' \
-H 'Connection: keep-alive' \
-H 'If-Modified-Since: Thu, 09 Oct 2025 16:42:02 GMT' \
-H 'If-None-Match: "bc2473a18e003bdb249eba5ce893033f:1760028122.592274"' \
-H 'Upgrade-Insecure-Requests: 1' \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0' \
--insecure
なにやら色々ありますが、-Hオプションが多いことに着目してください。これはヘッダ情報でした。「言語」や「コネクション情報」などがコマンドにも付与されています。これらの情報は「ブラウザがこのページとどのような条件で通信を行ったか」を意味します。
このコピーしたcURLコマンドをターミナルから実行すると当然HTMLが返ってきますが、ここでポイントとなるのは「Webサーバは通信相手がブラウザからアクセスしてきたと思っている」ということです。実際通信を送ったのはターミナルからにも関わらず、です。
Copy as cURL機能はこのように実際に行われた通信をコマンドの形で保存し、いつでも再現できるようにしてくれる機能なのです。
上記のコマンドをよく見てもらうとユーザーエージェントがどうとかと書いてあります。これを書き換えると「スマホからアクセスした」体を装うことも可能なわけです。
このページにはありませんが、ページによってはCookie情報が通信に含まれる場合もあります。これもCopy as cURLで取得可能で、Cookieの有効期限が切れるまではそのコマンドにより何回も同じ条件での通信が異なる場所から可能、だというわけです。
プログラム内に組み込む
cURLコマンドは便利ですが、たくさんオプションが付いてきて、さらに盛り込むデータが増えてきた、となると人の手に余る事があります。
1日目の記事では結局コマンドラインから真面目にcurlを作るのは大変なのでPythonプログラム内でコマンドの作成/実行を行おう、となりました。
このように、何度も/定期的にcurlで通信を行いたい!となった場合はプログラムに組み込んでしまうのも手です。各言語には外部呼び出し機能が備わっているので、curlなどのコマンドを実行し、その結果をそのままプログラム内で扱うことが可能です。
また、各プログラミング言語のライブラリには様々な通信を行ってくれるものがありますが、それらの実装をソースコードで見てみると内部的にcurlコマンドを実行していた、なんてこともよくあるらしいです。
おわりに
見直してみると自分が理解していたことが全然氷山の一角であったことがわかりました。
これからもこのコマンドを使う場面がたくさんあると思うので、まだ知らないこともたくさん調べて吸収していけたらいいなと思います。
それではまた、明日の記事でお会いしましょう。
参考文献
cURL(curlコマンド)とは - IT用語辞典 e-Words
PowerShellでcurl, wgetを使いたい #Windows - Qiita



