はじめに
curl
コマンドはシェルやシェルスクリプトから HTTP 通信を行うのによく使われるコマンドです。あらゆる環境(100 種類の OS)で動作し、macOS や Windows には標準でインストールされています。商用サポートもあり、互換性は非常に重視され、何年経っても同じ書き方で動きます。非常に長く使われており(1996 年生まれの 29 歳)、そして古い情報もたくさんあります。この記事ではそういった古い情報を、より簡単で新しい curl
コマンドの使い方にアップデートします。最初に結論を書いておくと、
もう -X POST -H "Content-Type: applicatoin/json"
なんて書かなくていいですよ。
この記事を書くにあたって以下の記事を参考にしています。この記事が書かれたのは 2015 年、現在はそれから 10 年後です。
今回使用した curl のバージョン
curl 8.12.1 です。
$ curl --version
curl 8.12.1 (x86_64-apple-darwin22.6.0) libcurl/8.12.1
OpenSSL/3.4.1 (SecureTransport) zlib/1.2.11 brotli/1.1.0
zstd/1.5.6 AppleIDN libssh2/1.11.1 nghttp2/1.64.0 librtmp/2.3
Release-Date: 2025-02-13
Protocols: dict file ftp ftps gopher gophers http https imap imaps
ipfs ipns ldap ldaps mqtt pop3 pop3s rtmp rtsp scp sftp
smb smbs smtp smtps telnet tftp ws wss
Features: alt-svc AsynchDNS brotli GSS-API HSTS HTTP2 HTTPS-proxy
IDN IPv6 Kerberos Largefile libz MultiSSL NTLM SPNEGO SSL
threadsafe TLS-SRP UnixSockets zstd
ちなみに上記の Protocols:
は curl
が対応しているプロトコルです。ビルドオプションによって変わり、Windows 版は少し少ないです。curl
は HTTP 関連だけではなく、ネットワークに関する多くの通信に対応しており、例えば telnet にも対応しているので、telnet
コマンドがインストールされてない環境でも、最後の手段として curl
コマンドで頑張れます。
最新版のダウンロード
各種 OS 用バイナリのダウンロードはこちらから
本当に多種多様な OS 用のバイナリが提供されています。
各 OS のバージョン情報
参考として、curl のバージョンと 各 OS のバージョン情報です。この記事ではいくつかの新しい機能を説明していますが、現時点では標準で使えない環境があるようです。最新版をインストールしましょう。
curl のバージョン | OS のバージョン、オプション |
---|---|
7.56.0 | Ubuntu 18.04 |
7.61.1 | AlmaLinux 8.10 |
7.67.0 (2019-11) | --no-progress-meter |
7.68.0 | Ubuntu 20.04 |
7.76 | AlmaLinux 9.5 |
7.81.0 | Ubuntu 22.04 |
7.82.0 (2022-03) | --json |
7.87.0 (2022-12) | --url-query |
7.88.1 | macOS 13.4 |
8.1.2 | macOS 13.5, 14, 15 |
8.3.0 (2023-11) |
--variable , --expand-*
|
8.5.0 | Ubuntu 24.04 |
8.10.1 | Windows 11 24H2 |
8.12.1 | Ubuntu 25.04(予定) |
jq のインストール
curl
で RESTful API を呼び出そうっていうのなら、jq
はもはや必須の道具ですね? jq の実装も本家あわせて私が知る限り 3 つあります。curl
と同じようにどこでも使えるツール兼言語です。
- https://jqlang.github.io/jq/ 1.7.1 (2023-12-13) C 製
- https://github.com/itchyny/gojq v0.12.17 (2024-12-01) Go 製
- https://github.com/01mf02/jaq 2.1 (2025-01-15) Rust 製
動作確認方法
まず最初にこの記事で使用している動作確認方法について説明します。この記事では curl
コマンドがどのようなデータを送信しているかを確認するために、次の nc
コマンドを使った簡易サーバーで実際に送信した通信内容を出力しています。
sh -c 'while command -p nc -l localhost 8080; do sleep 0.2; done' &
この記事で curl
コマンドが出力しているようなログは、実際には nc
コマンドが出力していることに注意してください。
$ sh -c 'while command -p nc -l localhost 8080; do sleep 0.2; done' &
[1] 95576 ← [1] はジョブ番号
$ curl -sS localhost:8080
GET / HTTP/1.1 ┐
Host: localhost:8080 │
User-Agent: curl/8.12.1 ├ 実は nc コマンドの出力
Accept: */* │
┘
^C ← curl が止まるので CTRL+C で止める
$ kill %1 ← nc コマンドを止めたい場合はジョブ番号を指定して kill する
[1]+ Terminated sh -c 'while command -p nc -l localhost 8080; do sleep 0.2; done'
ちなみに無限ループしているのは、curl
コマンド送信を CTRL+C で止めたときに nc
コマンドも終了してしまうからです。nc
コマンド(環境によっては netcat
)の引数は実装によって違うようなので動かなかったら調べてください。command -p
はほとんどの人は書く必要はないのですが、私は Homebrew で別の nc
コマンドをインストールしているので OS 標準版を呼び出すために使っています。Ubuntu と macOS はこれで動きました。Windows のやり方は調べていません。
もう一つの動作確認方法として、URL に file:/dev/null
(Windows では file:/NUL:
)を指定している箇所があります。これは file プロトコルでローカルの /dev/null
ファイル、つまり空ファイルを読み込んで出力しており何も出力されません。たしか昔は URL を省略できたと思うのですが今はできないのでその代わりです。
$ curl -w 'Hello World\n' file:/dev/null
Hello World
これでどこかのサーバーにあまり負荷をかけることなくデータのみのシンプルなログが得られます。まあ、一部は http://example.com にアクセスしてるんですが。この機能 curl
コマンド標準でできませんかね?
トレース表示ツール curl-trace
この記事を書いた後に思いついたのでこの記事では使っていませんが、こういうのを作ってみました。
#!/bin/sh
curl --no-progress-meter -o /dev/null --trace - "$@" | (
set -- awk
type gawk >/dev/null 2>&1 && set -- gawk -n
LC_ALL=C "$@" '
/^[0-9a-f]+:/ {
$0 = substr($0, 7, 47)
for (i = 1; i <= NF; i++) {
printf "%c", int("0x" (last = $i))
}
}
/^== Info: .* sent off/ {
if (last != "0a") print ""
print "========================================"
}
/^<= Recv data/ { exit }
'
)
引数は curl
コマンドへの引数そのままです。
$ curl-trace example.com
GET / HTTP/1.1
Host: example.com
User-Agent: curl/8.12.1
Accept: */*
========================================
HTTP/1.1 200 OK
Content-Type: text/html
ETag: "84238dfc8092e5d9c0dac8ef93371a07:1736799080.121134"
Last-Modified: Mon, 13 Jan 2025 20:11:20 GMT
Cache-Control: max-age=2962
Date: Fri, 21 Feb 2025 11:07:37 GMT
Content-Length: 1256
Connection: keep-alive
こういうのでいいんだよ、こういうので
仕組みは --trace
で通信データが 16 進数表記で出力されるので、それを元に戻しつつ必要な所だけ出力しています。この機能 curl コマンド標準でできませんかね?(2 回目)
-M (--manual), -h (--help) でドキュメント
通常は man curl
とかで良いのですが、最新バージョンをインストールしたときとかに適切なドキュメントが見れなくて困ることがあります。Homebrew 版は諸事情(?)でインストールしてもデフォルトではマニュアルが参照できないようです。正しくドキュメントをインストールして設定すればよいのですが、それよりも簡単な方法が -M
オプションを使用する方法です。この方法なら実行している curl
のバージョンのドキュメントを簡単に参照できます。(補足: Windows 版ではこの機能は無効にされているようです)
$ curl -M | less
特定のオプションのドキュメントだけを見たい場合、-h
(--help
) オプションが便利です。
$ curl -h -o | less
これらのオプションについては開発者ブログのこちらの記事もどうぞ。
その他のリンクです。
- https://curl.se/docs/optionswhen.html いつオプションが使えるようになったか
- https://curl.se/docs/manpage.html ウェブ上の manpage
- https://everything.curl.dev/ Everything curl - 公式のオンライン curl 本(PDF版もあり)
オプションの数
すべてのオプションは curl --help all
で出力できるので、すべてのオプションの数を数えるのは簡単です。
$ curl --help all
--abstract-unix-socket <path> Connect via abstract Unix domain socket
--alt-svc <filename> Enable alt-svc with this cache file
--anyauth Pick any authentication method
-a, --append Append to target file when uploading
︙
$ curl --help all | wc -l
267
GETメソッドと基本の話
ファイルのダウンロードなど、基本的な GET の話はほとんど変わっていません。
URLはクォートしましょう
文字が長くなるのでこの記事では省略していますが、(シェルのメタ文字が含まれるのであれば)URL はクォートしたほうが良いです。
# &はシェルのメタ文字なのでそのまま書けない。?も場合によってはまずい。
curl localhost:8080?key1=value1&key2=value2
# クォートするのが安全
curl 'localhost:8080?key1=value1&key2=value2'
わかっている人なら構わないのですが、シェルの文法がよくわからないとか言っている人は素直にクォートしましょう。
あと、余談ですが Windows のバッチファイルでは %
は %%
と書かないとダメとか。面倒なので確認していません。
よく使う -sSfL オプション
例のいつものよく使うオプションです。
オプション | 意味 |
---|---|
-s , --silent
|
プログレスメーターや、エラーや警告を出力しない |
-S , --show-error
|
エラーを出力するが、警告は出力するようにはならない |
-f , --fail
|
HTTP レスポンスコードが 400、500 番台のときにエラーにする |
-L , --location
|
リダイレクトを自動的に追跡する |
プログレスメーターだけを非表示にする (--no-progress-meter)
-s
(--silent
) オプションは、何も出力しないオプションで、プログレスメーターだけでなくエラーも警告も出力されなくなります。ただし -S
オプションを付けるとエラーは出力されます。しかし警告は出力されません。プログレスメーターだけを消したい場合には、2019 年の 7.67.0で 新たに --no-progress-meter
オプションが追加されています。つまり -sS
は --no-progress-meter
に置き換えられるということです。長すぎるので、対話シェルではエイリアスを設定し、シェルスクリプトでは次のようなシェル関数を定義してデフォルトオプションを追加するとよいでしょう。
# curl コマンドへデフォルトのオプションを追加する
curl() {
command curl --no-progress-meter "$@"
}
# 以下のように実行するだけで上記のオプションが追加される
curl example.com
--silent
については開発者ブログのこちらの記事もどうぞ。
ちなみに ootw とは Option-Of-The-Week の略とのことです。一般的には「Outfit Of The Week」の略で、1 週間のお気に入りファッションコーディネートを紹介する時に使われる用語らしいです。
通信データを圧縮する (--compressed
)
見逃されがちなのが、curl
の通信は圧縮されていないということです。--compressed
オプションを指定することで圧縮されます。(補足: 以下の出力は読みやすいように不要な行を削っています。)
$ curl -sS -v -o /dev/null example.com
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/8.12.1
> Accept: */*
< HTTP/1.1 200 OK
< Content-Type: text/html
< ETag: "84238dfc8092e5d9c0dac8ef93371a07:1736799080.121134"
< Last-Modified: Mon, 13 Jan 2025 20:11:20 GMT
< Cache-Control: max-age=1262
< Date: Thu, 20 Feb 2025 11:44:57 GMT
< Content-Length: 1256 ← 元のサイズ
< Connection: keep-alive
$ curl -sS -v -o /dev/null --compressed example.com
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/8.12.1
> Accept: */*
> Accept-Encoding: deflate, gzip ← 圧縮を受け付ける
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Content-Type: text/html
< ETag: "84238dfc8092e5d9c0dac8ef93371a07:1736799080.121134"
< Last-Modified: Mon, 13 Jan 2025 20:11:20 GMT
< Vary: Accept-Encoding
< Content-Encoding: gzip ← 圧縮されている
< Content-Length: 648 ← サイズが減っている
< Cache-Control: max-age=1128
< Date: Thu, 20 Feb 2025 11:46:23 GMT
< Connection: keep-alive
-k (--insecure) オプションを使わない! 証明書エラーを無視しない!
$\mathtt{\huge{危険な‐kオプションは使ってはいけません}}$
-k
は kiken の略です。説明を読まない人のためにはこの一言だけで十分でしょう。正しい対処法は「サーバー側の設定を正しく行う」または「自分の環境の設定を正しく行う」です。時計がずれていたり OS が古かったりするのが原因なのでアップデートしましょう。
わかっている人にとってはあたり前のことなのでしょうが、なんの説明もなしに危険な -k
オプションを便利だよと紹介する記事が多すぎます。読まない人は読まないですからね。だから読まない人のために書きました。どうしても使用する場合は代わりに ‐‐insecure
オプションと書きます。「危険」という意味の分かりやすい別名です。対話シェルで時間がない時に使うことはあっても、シェルスクリプトの中に書くことはないはずです。ましてや本番環境では使用しません。
この記事を書いている最中、開発者ブログを読んでいたら以下の記事を見つけたので、やっぱ開発者も同じことを思っているんだなぁと思いました。
この記事によると、-k
オプションを使用すると、curl
はサーバーの以下の TLS 証明書の検証をスキップします。
- 証明書が信頼された認証局(CA)によって署名されているか
- 接続先のホスト名と証明書が一致しているか
- 証明書の有効期限が切れていないか
また libcurl を使用する場合、以下の値を 0
(false) にしてはいけません。
CURLOPT_SSL_VERIFYHOST
CURLOPT_SSL_VERIFYPEER
このオプションは以下の状況下でデバッグ目的で一時的に利用するためです。
- サーバーの証明書を検証するための適切な CA 証明書をまだ持っていない
- サーバーが誤った設定になっており、正規のチェックに失敗してしまう
ファイルに出力する -o, -O オプション
-o
(--output
) オプションで指定したファイルに保存できます。-O
(--remote-name
) オプションだと、指定した URL のファイル名部分のみが使われます。
$ curl -o index.html http://example.com
$ curl -O http://example.com/file.tar.gz
-o
オプションを指定しない場合、標準出力に出力されますが、これを出力したくない場合にはファイル名に /dev/null
を指定します。
$ curl -o /dev/null http://example.com
ちなみにリモートが指定する名前を使用したい場合には -J
(--remote-header-name
) オプションを指定します。この場合、既存のファイルは上書きされません(されたら危険ですね)。上書きを許可する --clobber
オプションもあるようですが。まあ、あまり使わないほうが良いでしょう。
クエリー文字列を組み立てる (--url-query)
クエリー文字列を組み立てるときには、2022 年のバージョン 7.87.0 で追加された --url-query
を使用します。これは昔の -G
と -d
を併用した回避策を置き換え、従来はできなかった POST などと組み合せて使える方法です。キーはそのままですが値は URL エンコードされます。
$ curl -sS --url-query key1=value1 --url-query key2=value2 localhost:8080
GET /?key1=value1&key2=value2 HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
$ curl -sS --url-query key=value -d data=value localhost:8080
POST /?key=value HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
Content-Length: 10
Content-Type: application/x-www-form-urlencoded
data=value
$ curl -sS --url-query key=値 localhost:8080
GET /?key=%e5%80%a4 HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
-i (--include) でレスポンスヘッダを出力
-i
(--include
) オプションを使用すると、レスポンスのボディの前に(レスポンスのボディの一部として)レスポンスヘッダを出力します。レスポンスヘッダとレスポンスのボディは間には空行が挟まり区別できます。最近 --show-headers
という分かりやすい別名が与えられました。
$ curl -i amazon.com
HTTP/1.1 301 Moved Permanently
Server: Server
Date: Thu, 20 Feb 2025 11:14:11 GMT
Content-Type: text/html
Content-Length: 163
Connection: keep-alive
Location: https://amazon.com/
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>Server</center>
</body>
</html>
この情報を使ってシェルスクリプトで分岐処理を行えます。もっともこんなことをやっているコードを見たことがありませんが。
CR=$(printf '\r') # ヘッダの改行コード「CR LF」の CR を消すための準備
curl -sS -i example.com | {
read -r http_version http_code message # ヘッダの1行目の取得
while IFS= read -r line; do # 空行まで読み飛ばすループ
[ "${line%"$CR"}" ] || break # CRを削除した行が空行の場合にループを抜ける
done
case $http_code in
2*) cat ;; # 200番台なら標準出力に出力
*) cat >&2 ;; # それ以外なら標準エラー出力に出力
esac
}
ヘッダの解析が面倒なので、-w
の出力をレスポンスボディ前に行うやつが欲しい所です。なお、-i
はレスポンスのボディの一部として出力されるため、-o
で指定した出力先に出力されます。
$ curl -sS -i -o /dev/null example.com
何も出力されない
-w (--write-out) で追加の情報を出力
-w
オプションを指定すると追加の情報を出力に加えます。-i
オプションとは反対にレスポンスの後に出力されます。レスポンスの内容を出力したくない場合には、-o /dev/null
を指定します。どのような情報を参照できるかについては、%{json}
と %{header_json}
を出力するのが簡単です。そのままでは見づらいので jq
コマンドに通すとよいでしょう。補足ですが、jq .
の後ろの .
は今は不要です。
$ curl -sS -w '%{json}' -o /dev/null http://example.com | jq
︙ 長いので省略
$ curl -sS -w '%{header_json}' -o /dev/null http://example.com | jq
︙ 長いので省略
知りたい項目名がわかったら書式を指定して出力すれば OK です。ヘッダの情報は %header{キー}
で指定します。
$ curl -sS -w '%{method}: %{url}\n' -o /dev/null http://example.com
GET http://example.com
$ curl -sS -w '%header{content-length}\n' -o /dev/null http://example.com
1256
-w
はデフォルトでは標準出力に出力しますが、出力先を標準エラー出力(%{stdout}
)に切り替えたり標準出力(%{stdout}
)に戻したりできます。またファイル(%output{ファイル名}
)に出力したり、追記( %output{>>ファイル名}
)もできます。
$ curl -sS -w '%{stderr}stderr\n%{stdout}stdout\n' file:/dev/null >/dev/null
stderr
$ curl -sS -w '%{stderr}stderr\n%{stdout}stdout\n' file:/dev/null 2>/dev/null
stdout
$ curl -sS -w '%output{/tmp/output.txt}Hello\n' file:/dev/null
$ cat /tmp/output.txt
Hello
$ curl -sS -w '%output{>>/tmp/output.txt}World\n' file:/dev/null
$ cat /tmp/output.txt
Hello
World
余談ですが、個人的にはファイルディスクリプタに出力できるようにして欲しくて、ほとんどの環境では /dev/fd/N
が実装されているので代わりに使えるのですが、こういう事ができます。
#!/bin/sh
{
http_code=$(
{
format='%output{/dev/fd/3}%{http_code}'
curl -sS -w "$format" 'http://example.com' >&4 4>&-
} 3>&1
)
} 4>&1
# http_code が取れる!
echo "$http_code"
こんなコードを書こうという人はあまりいないかもしれませんが(提案しようかな?)。-w
はレスポンスボディの一部ではないため、このような使い方を想定しているのかも知れません。一時ファイルを使うという点が違いますが上記のコードでやりたいことと同じようなことができます。
http_code=$(curl -sS -w '%{http_code}' -o /tmp/index.html example.com)
# http_code が取れる!
echo "$http_code"
変数と変数展開機能 (--variable, --expand-*)
2023 年 11 月にリリースされた 8.3.0 から使えるようになった非常に便利な機能が「変数」 です。これは --variable
を使って curl
コマンドだけで使える変数を定義できます。変数を展開したい場合は、--expand-
を頭につけてオプションを指定します。つまり --url
オプションはデフォルトでは変数は展開されませんが、展開させたい場合は --expand-url
という形で指定します。
$ curl -sS --variable path=web --expand-url 'localhost:8080/{{path}}'
GET /web HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
この変数は環境変数を取り込めます。環境変数が定義されていない場合はエラーになりますが、定義されていないときのデフォルト値も設定すればエラーになりません。
$ curl -sS --variable '%USER' --expand-url 'localhost:8080/{{USER}}'
GET /koichi HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
$ curl -sS --variable '%name=guest' --expand-url 'localhost:8080/{{name}}'
GET /guest HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: *
$ name=ken curl -sS --variable '%name=guest' --expand-url 'localhost:8080/{{name}}'
GET /ken HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
普通にシェル変数でいいじゃないか? と思っているころだと思いますが、便利な機能の一つが {{v:url}}
みたいな感じで関数を使用できることです。関数は {{v:trim:url}}
みたいにして複数組み合せられます。現在、定義されている関数は少ないですが、もっと拡張されていくでしょう。なお変数はもう一つ素晴らしい使い方があるのですが、それは後ほど。
URLエンコードするだけ {{v:url}}
おまけで jq
コマンド版も紹介します。
$ curl --variable v='あいおえお' --expand-write-out '{{v:url}}\n' file:/dev/null
%E3%81%82%E3%81%84%E3%81%8A%E3%81%88%E3%81%8A
$ jq -rn --arg v あいうえお '@uri "\($v)"'
%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A
Base64エンコードするだけ {{v:b64}}
おまけで jq
コマンド版も紹介します。
$ curl --variable v='あいおえお' --expand-write-out '{{v:b64}}\n' file:/dev/null
44GC44GE44GK44GI44GK
$ jq -rn --arg v あいうえお '@base64 "\($v)"'
44GC44GE44GG44GI44GK
JSONエスケープするだけ {{v:json}}
おまけで jq
コマンド版も紹介しますが、少し出力が異なります。
$ curl --variable v=' \ " ' --expand-write-out '{{v:json}}\n' file:/dev/null
\\ \"
$ jq -rn --arg v ' \ " ' '@json "\($v)"'
" \\ \" "
trimするだけ {{v:trim}}
$ curl --variable v=' hello ' --expand-write-out '[{{v:trim}}]\n' file:/dev/null
[hello]
変数の内容をファイルから読み込む
変数の内容をファイルから読み込むこともできます。
$ cat file.txt
up
down
left
right
$ curl --variable v@file.txt --expand-write-out '[{{v:trim}}]\n' file:/dev/null
[up
down
left
right
]
範囲指定して読み込めます。
$ curl --variable v[6-10]@file.txt --expand-write-out '[{{v}}]\n' file:/dev/null
[down ]
$ curl --variable v[6-10]@file.txt --expand-write-out '[{{v:trim}}]\n' file:/dev/null
[down]
ファイルの中から特定の範囲のデータを取り出すというユースケースが謎でしたが、ファイルは固定長ファイルで空きはスペースで埋められていると考えれば、もう一つのユースケースが謎だった trim の使い道が見えてくるわけで・・・うーん? 行番号指定での読み込みとかで良くない?
追記 コメント より、ユースケースは分割アップデートではないかと。なるほど。
HEADメソッドの話
HEAD メソッドとは、ウェブサーバーに接続するけれども「本文は返さなくて良い、ウェブページが更新されているかを知りたいだけなんだ。」とサーバーに問い合わせる時に使う HTTP メソッドです。サーバーの負荷を減らす素晴らしい機能ですが、おそらく curl
コマンドの通常の利用者が使うことはあまりないでしょう。
-I(アイ)はヘッダを見る方法ではない
非常に多く見かける間違いなのですが、-i
(小文字のアイ)オプションと -I
(大文字のアイ)オプションは全く違う機能です。出力にレスポンスヘッダを含める -i
(--include
) に対して、-I
(--head
) オプションは HEAD メソッドを実行するオプションです。実行している HTTP メソッドが違います。GET メソッドのレスポンスヘッダを見るのに HEAD メソッドを実行したらだめでしょう? まあほとんど GET と同じようなレスポンスヘッダを返すのですが、-I
では POST などのレスポンスヘッダは見られません。ちゃんと説明するなら -I
は「HEAD メソッドのレスポンスヘッダ」を出力するオプションです。
$ curl -I localhost:8080
HEAD / HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
-I
オプションを指定するとレスポンスボディではなくレスポンスヘッダを出力するという動作に切り替わったり、-X
オプションで HTTP メソッドを上書きできるようなのでレスポンスヘッダを見られないこともなかったりと、微妙な動作をしており、それが勘違いしてしまう理由だと思いますが、レスポンスヘッダを見るなら、-D
オプションか -v
オプションが適切です。
デバッグ方法の話
-D (--dump-header)
-i
と似た機能でこちらもヘッダを出力しますが、ヘッダはレスポンスのボディに組み込まれることはなく、指定した別のファイルに出力されます。出力先に -
を指定すると標準出力に出力されます。バージョン 8.10.0 から出力先に %
を指定すると標準エラー出力に出力されるようになりました。
$ curl -sSfL -D - -o /dev/null example.com
HTTP/1.1 200 OK
Content-Type: text/html
ETag: "84238dfc8092e5d9c0dac8ef93371a07:1736799080.121134"
Last-Modified: Mon, 13 Jan 2025 20:11:20 GMT
Cache-Control: max-age=1500
Date: Thu, 20 Feb 2025 11:13:47 GMT
Content-Length: 1256
Connection: keep-alive
$ curl -sSfL -D % -o /dev/null example.com
HTTP/1.1 200 OK
Content-Type: text/html
ETag: "84238dfc8092e5d9c0dac8ef93371a07:1736799080.121134"
Last-Modified: Mon, 13 Jan 2025 20:11:20 GMT
Cache-Control: max-age=1514
Date: Thu, 20 Feb 2025 11:17:45 GMT
Content-Length: 1256
Connection: keep-alive
-v (--verbose)
-v
オプションを指定すると、通信の詳細情報が取得できます。バージョン 8.10.0 から -vv
、-vvv
、-vvv
みたいに詳細レベルが増加し、今までは --trace-time
や --trace-ascii
などを指定しなければ見られなかった情報が簡単に見られるようになりました。実際の出力は量が多いので省略します。ぜひ試してみてください。
$ curl -sSfL -v -o /dev/null example.com
* Host example.com:80 was resolved.
* IPv6: (none)
* IPv4: 96.7.128.175, 96.7.128.198, 23.192.228.80, 23.215.0.138, 23.192.228.84, 23.215.0.136
* Trying 96.7.128.175:80...
* Connected to example.com (96.7.128.175) port 80
* using HTTP/1.x
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/8.12.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Content-Type: text/html
< ETag: "84238dfc8092e5d9c0dac8ef93371a07:1736799080.121134"
< Last-Modified: Mon, 13 Jan 2025 20:11:20 GMT
< Cache-Control: max-age=2898
< Date: Thu, 20 Feb 2025 11:26:31 GMT
< Content-Length: 1256
< Connection: keep-alive
<
{ [1256 bytes data]
* Connection #0 to host example.com left intact
*
--trace, --trace-ascii
--trace
を指定すると通信内容をバイナリで出力し、--trace-ascii
を指定すると ASCII で出力します。出力先はファイルまたは標準出力「-」や標準エラー出力「%」を指定します。おそらく -vvv
とかに置き換え可能です。
$ curl -sSfL --trace - -o /dev/null example.com
== Info: Host example.com:80 was resolved.
== Info: IPv6: (none)
== Info: IPv4: 96.7.128.198, 23.215.0.136, 23.192.228.80, 23.215.0.138, 23.192.228.84, 96.7.128.175
== Info: Trying 96.7.128.198:80...
== Info: Connected to example.com (96.7.128.198) port 80
== Info: using HTTP/1.x
=> Send header, 75 bytes (0x4b)
0000: 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a GET / HTTP/1.1..
0010: 48 6f 73 74 3a 20 65 78 61 6d 70 6c 65 2e 63 6f Host: example.co
0020: 6d 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 63 m..User-Agent: c
0030: 75 72 6c 2f 38 2e 31 32 2e 31 0d 0a 41 63 63 65 url/8.12.1..Acce
0040: 70 74 3a 20 2a 2f 2a 0d 0a 0d 0a pt: */*....
== Info: Request completely sent off
<= Recv header, 17 bytes (0x11)
0000: 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d HTTP/1.1 200 OK.
0010: 0a
$ curl -sSfL --trace-ascii - -o /dev/null example.com
== Info: Host example.com:80 was resolved.
== Info: IPv6: (none)
== Info: IPv4: 23.215.0.136, 23.192.228.80, 23.215.0.138, 23.192.228.84, 96.7.128.175, 96.7.128.198
== Info: Trying 23.215.0.136:80...
== Info: Connected to example.com (23.215.0.136) port 80
== Info: using HTTP/1.x
=> Send header, 75 bytes (0x4b)
0000: GET / HTTP/1.1
0010: Host: example.com
0023: User-Agent: curl/8.12.1
003c: Accept: */*
0049:
== Info: Request completely sent off
<= Recv header, 17 bytes (0x11)
0000: HTTP/1.1 200 OK
認証とセキュリティの話
どのくらいのセキュリティレベルが必要かは、時と場合によります。いつでも真面目にやる必要はありません。ただし真面目なやり方を知っておく必要はあり、重要な場合には真面目なやり方をする必要があります。
手抜きしても構いませんが、それは手抜きが許されるときだけです。普段は「手抜きでいいじゃないか!」が許されたからといって、それを本番環境で使って良いことにはなりません。手抜きができるのは正しいやり方を知っている人だけであり、正しいやり方を知らないのであれば、それが精一杯ということであり、手を抜いていることにはなりません。
つまり、対話シェルでの開発中の書き方と、信頼性が高いシェルスクリプトの書き方は違うということです。
コマンド引数の秘密情報は漏洩する
この話は公式本の「Everything curl」でも警告されています。
Unix/Linuxに共通する話として、コマンドの引数に書いたパスワードは同じコンピュータを使う他のユーザーから読み取れます。他のユーザーとは root ユーザーのことではありません。他の一般ユーザーです。したがってパスワードをコマンドの引数に書いてはいけません。もちろん HTTP ヘッダに指定するアクセストークンなども同じです。
$ curl --user 'key:secret' localhost:8080
↑
他のユーザーに漏洩しています!
$ curl -H "Authorization: Bearer YourAccessToken" localhost:8080
↑
他のユーザーに漏洩しています!
$ whoami
guest
$ ps -a -o user,command | grep curl
koichi curl --user key:secret localhost:8080
guest grep --color=auto curl
$ ps -a -o user,command | grep curl
koichi curl -H Authorization: Bearer YourAccessToken localhost:8080
guest grep --color=auto curl
macOS ではパスワードが隠されているようですが、これは curl
コマンドによる処理なので一瞬は見えるはずですし、アクセストークンの方は隠されていません。
「自分しかこのパソコンを使ってないからいいじゃないか!」というセリフは、この問題に気づいている人だけが言って良い言葉で、この問題を警告せずにコマンドの引数にパスワードやアクセストークンを指定しているサンプルコードが大量にあるのを見ると、気づいていない人が大半でしょう?
実際の脅威で考えると、学校とかで1つのサーバーを複数人で利用している場合とか、共有のレンタルサーバーでシェルスクリプトから、何かしらのコマンドのコマンドの引数に書いた秘密情報は他のユーザーに漏洩しています。ぜひこの話を周りの人に広めてください。
.netrc や config で秘密情報を隠す
対処方法の1つは Everything curl にも書いてあるとおり .netrc
ファイルや config
ファイルを使うことです。.netrc
ファイルは curl
に限らず、wget
やいくつかのネットワークツールなどで使われているパスワードなどを保存するファイルです。
machine localhost
login key
password secret
$ curl --user 'key:secret' localhost:8080
GET / HTTP/1.1
Host: localhost:8080
Authorization: Basic a2V5OnNlY3JldA==
User-Agent: curl/8.12.1
Accept: */*
$ curl --netrc localhost:8080
GET / HTTP/1.1
Host: localhost:8080
Authorization: Basic a2V5OnNlY3JldA== ← 一致している
User-Agent: curl/8.12.1
Accept: */*
HTTP ヘッダに書くアクセストークンなどはこの方法が使えないので config
ファイルを使います。config
ファイルはホームディレクトリの .curlrc
を読み込んだりしますが、接続先ごとに変わるはずので --config
オプションで指定します。
header = "Authorization: Bearer YourAccessToken"
$ curl -H "Authorization: Bearer YourAccessToken" localhost:8080
GET / HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
Authorization: Bearer YourAccessToken
$ curl --config /tmp/config localhost:8080
GET / HTTP/1.1
Host: localhost:8080
Authorization: Bearer YourAccessToken ← 一致している
User-Agent: curl/8.12.1
Accept: */*
環境変数で秘密情報を隠す
秘密情報は環境変数を使っても隠すことができます。これが curl
に追加された変数機能のもう一つの素晴らしい使い方です。もちろんシェルの変数機能を使ったらだめです。これは変数展開がコマンド実行の前に行われるからです。
$ user='key:secret'
$ curl --user "$user" localhost:8080
$ token=YourAccessToken
$ curl -H "Authorization: Bearer $token" localhost:8080
そうではなく、curl
コマンドの環境変数の取り込みと変数展開機能を使います。
$ user='key:secret' curl --variable '%user' --expand-user '{{user}}' localhost:8080
GET / HTTP/1.1
Host: localhost:8080
Authorization: Basic a2V5OnNlY3JldA==
User-Agent: curl/8.12.1
Accept: */*
$ token='YourAccessToken' curl --variable '%token' \
--expand-header 'Authorization: Bearer {{token}}' localhost:8080
GET / HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
Authorization: Bearer YourAccessToken
コマンドが長いとクレームが来そうですが、そもそも「Authorization: Bearer ・・・」だって長いわけで、これを省略する config
を使えばよいのです。この場合、秘密情報は環境変数で渡すので config
の共通化も可能でしょう。シェルスクリプトであれば長くても問題ないはずです。
ここでコマンド名の前の環境変数代入(token='YourAccessToken' curl
・・・)は漏れないの?と思うかも知れませんが、この部分はシェルが解釈して実行しているので問題ありません。気になるようなら export
コマンドで環境変数をエクスポートしても構いません。ただし注意しなければ不要なコマンドにまで秘密情報を渡してしまうことになりかねません。シェルスクリプトであれば一時的に環境変数にしたほうが良いでしょう。コマンドの前で設定する環境変数は一時的なもので、コマンドを終了した後は環境変数ではありません。
token='YourAccessToken'
# 一時的に環境変数にする
# ただし curl がシェル関数で再定義されている場合、シェルによっては
# 一時的ではなくシェル関数を抜けても環境変数のままなので注意
token="$token" curl --variable '%token' \
--expand-header 'Authorization: Bearer {{token}}' localhost:8080
# exportを使う場合は、使用後にエクスポート属性を削除して環境変数ではなくす
export token
curl --variable '%token' \
--expand-header 'Authorization: Bearer {{token}}' localhost:8080
export -n token # bash でのみ使える
typeset +x token # bash、ksh93、zsh で使える
困ったことに POSIX で標準化されている範囲では変数を削除せずにエクスポート属性のみを削除する方法がありません。bash などを使えば簡単ですが、どうしても dash などで実現したい人のためにエクスポート属性のみを削除する関数はこちらです。
# エクスポート属性のみを削除する関数
unexport() {
while [ $# -gt 0 ]; do
eval "set -- \"\$$1\" \"\$@\"; unset $1; $1=\$1; shift 2"
done
}
export var1=123 var2=456
unexport var1 var2
echo "$var1 $var2" # => 123 456 (変数の中身はそのまま)
標準入力やファイルで秘密情報を隠す
-H
などいくつかのオプションは標準入力からのデータ読み取りに対応しており、標準入力やファイルを使うことでも秘密情報を隠せます。ファイルを使う場合は他の人が読み取れないようにしてください。@-
で標準入力、@ファイル名
でファイルから読み取ります。
$ echo "Authorization: Bearer YourAccessToken" | curl -H @- localhost:8080
GET / HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
Authorization: Bearer YourAccessToken
ここで echo
コマンドの引数は他のユーザーから読み取られることはないのか? と思うかもしれませんが、echo
コマンドは事実上すべてのシェルでビルトインコマンドなので ps
コマンドなどのプロセス一覧に出現することはありません。ただし POSIX 的には echo
コマンドをビルトインコマンドとして実装することは要求されていないので、可能性としては echo
コマンドが外部コマンドである POSIX シェルの存在はありえます。printf
コマンドは OpenBSD sh/ksh と mksh では外部コマンドなので読み取られる危険性があります。
echo
コマンドの代わりにヒアドキュメントを使う方法も安全です。これは完全にシェルの機能なので echo
コマンドのような外部コマンドの可能性を心配する必要はありません。
$ curl -H @- localhost:8080 << 'HERE'
Authorization: Bearer YourAccessToken
HERE
GET / HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
Authorization: Bearer YourAccessToken
bash、ksh93、zsh などであればヒアストリングから読み取る方もあります。
$ curl -H @- localhost:8080 <<< "Authorization: Bearer YourAccessToken"
GET / HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
Authorization: Bearer YourAccessToken
HTML フォーム送信の話
curl
コマンドは人がウェブページ、つまり HTML にアクセスするような使い方ができます。すでに説明した単純な GET はリンクをクリックするのと同等の操作です。HTML にはフォーム(<form>
タグ)による送信機能があります。フォームの送信からは GET と POST が行えます。ここで説明するのはそのようなフォーム操作を curl
コマンドから行う方法です。HTML フォームに関連する HTTP メソッド、つまり GET と POST は、RESTful API よりも数年早くに誕生しました。curl
コマンドへの実装も HTML フォームに関連する機能が先行しています。近年の RESTful API の使い方は、HTML フォームの送信とあまり関係ないのですが、HTML フォーム送信の話は curl
コマンドの使い方の基本でもあります。
GET メソッド (-G)
フォームの GET メソッドは HTML で次のように書きます。
<form method="GET" action="/get.cgi">
<input type="text" name="name1" value="値1">
<input type="text" name="name2" value="値2">
<input type="submit">
</form>
これと同じことを curl
コマンドで行う場合には次のように書きます。
$ curl -G --data-urlencode name1=値1 --data-urlencode name2=値2 localhost:8080/get.cgi
GET /get.cgi?name1=%e5%80%a41&name2=%e5%80%a42 HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
-G
(--get
) オプションを指定しているのがポイントです。これがなければ POST になってしまいます。
次で説明する --data-urlencode
を含む、-d
(--data
) 系オプションは 2000 年台の初期に POST を行うためのオプションとして追加された HTML フォーム(<form>
タグの機能)に対応する機能です。HTML フォームは GET も送信でき、その場合は送信するとクエリー文字列に変換されます。この動作をシミュレートしたのが -G
オプションです。<form>
タグの場合は method
属性を省略したときのデフォルトが GET であるという違いはありますが、-G
オプションの役目は -d
系オプションの指定によって POST になったものを GET に戻すことです。-X GET
でも GET メソッドで送信できますが、-G
(--get
) オプションは HTML フォームと関連した機能という考え方が含まれています。詳細は以下の開発者ブログを参照してください。
POST メソッド (--data-urlencode, application/x-www-form-urlencoded)
フォームの POST メソッドは HTML で次のように書きます。
<form method="POST" action="/post.cgi">
<input type="text" name="name1" value="値1">
<input type="text" name="name2" value="値2">
<input type="submit">
</form>
これと同じことを curl
コマンドで行う場合には次のように書きます。
$ curl --data-urlencode name1=値1 --data-urlencode name2=値2 localhost:8080/post.cgi
POST /post.cgi HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
Content-Length: 33
Content-Type: application/x-www-form-urlencoded
name1=%E5%80%A41&name2=%E5%80%A42
「データを送信した場合は POST であるはずだ」という設計方針なのでしょう。Content-type が「application/x-www-form-urlencoded」になっているところに注意してください。したがって --data-urlencod
を使うのが一番簡単です。--data
などを使う場合は自分で URL エンコードする必要があります。curl
組み込みに変数と変数展開機能を使っても URL エンコードできます。--data-urlencode
の引数はただの文字列ではなく、ファイルの読み込みなど特殊な書式が使えます。
--data-urlencode <data> |
意味 |
---|---|
content |
文字列(= や @ が含まれると違う意味になる) |
=content |
文字列(最初の = は無視される) |
name=content |
名前=文字列 形式 |
@filename |
文字列(文字列はファイルから読み込む) |
name@filename |
名前=文字列 形式(文字列はファイルから読み込む) |
便利な機能ですがシェルスクリプトなどでシェル変数をそのまま使用すると、ファイルを送信してしまう可能性があります。
value='@/etc/hosts'
curl --data-urlencode "$value" localhost:8080/post.cgi
# 代わりにこうする
curl --data-urlencode "=$value" localhost:8080/post.cgi
POST メソッド (-F, multipart/form-data)
フォームの POST メソッドで画像などをアップロードするときには HTML で次のように書きます。書き方が違うのは画像のような大きなデータは URL エンコードして渡すのは適していないからです。
<form method="POST" action="/post.cgi" enctype="multipart/form-data">
<input type="text" name="name1" value="値1">
<input type="text" name="name2" value="値2">
<input type="file" name="image">
<input type="submit">
</form>
enctype
が追加されているのがポイントです。 これと同じことを curl
コマンドで行う場合には次のように書きます。
$ curl -F name1=値1 -F name2=値2 -F image=@image.png localhost:8080/post.cgi
POST /post.cgi HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
Content-Length: 413
Content-Type: multipart/form-data; boundary=------------------------dE72sJJFXYuwGekPOTi67v
--------------------------dE72sJJFXYuwGekPOTi67v
Content-Disposition: form-data; name="name1"
値1
--------------------------dE72sJJFXYuwGekPOTi67v
Content-Disposition: form-data; name="name2"
値2
--------------------------dE72sJJFXYuwGekPOTi67v
Content-Disposition: form-data; name="image"; filename="image.png"
Content-Type: image/png
(省略)
--------------------------dE72sJJFXYuwGekPOTi67v--
-F
(--form
) オプションを使用すると multipart/form-data で送信されます。ちなみに -F
オプションと --data
系オプションを併用できない理由は、このように送信形式が異なるためです。filename
や Content-Type
は次のような書き方で指定できます。
-F 'image=@image.png;type=image/jpg;filename=img.jpg'
このように、-F
オプションの引数はただの文字列ではなく、ファイルの読み込みなど特殊な書式が使えます。つまりシェル変数をそのまま使用すると、ファイルを送信してしまう可能性があります。代わりに --form-string
を使えばこのような特殊な書き方が無効になるので適切なオプションを使い分ける必要があります。詳細はドキュメントを参照してください。
name='@/etc/hosts'
curl -F name="$name" localhost:8080/post.cgi
# 代わりにこうする
curl --form-string name="$name" localhost:8080/post.cgi
--data 系オプション
--date-urlencode
以外のオプションは URL エンコードを行わないため、通常とは異なるデータの送信に使えます。ただし --data
系オプションはいずれも Content-Type をデフォルトで application/x-www-form-urlencoded
に設定するため、自分で URL エンコードを行うか、-H
(--header
) オプションで Content-Type を別のものにして使う必要があるでしょう。それぞれの --data 系オプションの違いは次のとおりです。詳細はドキュメントを参照してください。
オプション |
@ファイル 書式 |
---|---|
-d , --data , --data-ascii
|
使える(改行が消える) |
--data-binary |
使える(改行は消えない) |
--data-raw |
使えない(引数の文字列をそのまま送信する時に使う) |
Cookie を使う
注意: ほとんど検証していません。
curl
コマンドで Cookie を使う時は、-b (--cookie) <data|filename>
オプション(Cookie の送信)や -c (--cookie-jar) <filename>
オプション(Cookie の保存)を使うようです。Cookie はファイルに保存することで維持されますが、curl
コマンドは 1 回のコマンド実行で複数の URL にアクセスでき、Cookie を保存するファイル名を /dev/null
にすることで、メモリ内だけで Cookie を維持できるようです。
$ curl -sSFl -c /dev/null localhost:8080/post.cgi localhost:8080/post.cgi
CGI 作るのも面倒だったので、どこぞのサンプルサイトで試してみましたが動いているようです。
RESTful API の話
おそらく現在の curl
コマンドのメインの使い方でしょう。前提知識として「認証とセキュリティの話」は読んでおいてください。HTML フォーム送信の話は忘れても良いぐらいです。その方が簡単に使い方を理解できます。
JSON データを送信する (--json, -H)
2022 年のバージョン 7.82.0 で追加された --json
オプションで、curl
コマンドでの RESTful API の使い方は変わりました。基本として -H
(--header
) も -d
(--date
) も使いません。HTML フォーム送信の話は何だったんだ?というぐらい簡単です。基本はこれだけです。
$ curl --json '{"key": "value"}' localhost:8080/api
POST /api HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Content-Type: application/json
Accept: application/json
Content-Length: 16
{"key": "value"}
やることは --json
オプションで JSON データを送信するだけです。-H
オプションで指定した Content-Type: application/json
と Accept: application/json
は自動的に設定されます。--json
オプションはこの2つの設定を行い --data-binary
オプションを指定することに相当します。したがって、POST メソッドであり、@
で始めることでファイルや標準入力からの読み込みも行えます。
# ファイルからの読み込み
curl --json @file.json localhost:8080/api
# 標準入力からの読み込み
curl --json @- localhost:8080/api < file.json
# ヒアドキュメントからの読み込み
curl --json @- localhost:8080/api << 'HERE'
{"key": "value"}
HERE
# パイプからの読み込み
echo '{"key": "value"}' | curl --json @- localhost:8080/api
もし 7.82.0 よりも古いバージョンしか使えない場合は、このように書くのと同じです。
$ curl -H 'Content-Type: application/json' -H 'Accept: application/json' \
--data-binary '{"key": "value"}' localhost:8080/api
POST /api HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Content-Type: application/json
Accept: application/json
Content-Length: 16
{"key": "value"}
もちろん Content-Type や Accept を違うものにする必要がある場合は -H
(--header
) を指定して調整する必要があります。
JSON データは jq や jo で組み立てよう
curl
コマンドの引数の JSON データを手書きするなんて面倒ですよ。キーのダブルクォートとか。せめて jq
コマンドを使って書きましょう。別にどんなツールを使っても構いませんが。
$ jq -n '{key: 123}' | curl --json @- localhost:8080/api
POST /api HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Content-Type: application/json
Accept: application/json
Content-Length: 17
{
"key": 123
}
jq
コマンドを使った JSON データの書き方の例をいくつか紹介します。
$ jq -nf /dev/stdin << HERE
{
key: 123
}
HERE
{
"key": 123
}
$ jq -n --arg key1 value1 --arg key2 value2 '$ARGS.named'
{
"key1": "value1",
"key2": "value2"
}
$ jq -n --arg key1 123 --argjson key2 456 '$ARGS.named'
{
"key1": "123",
"key2": 456
}
JSON を組み立てるコマンドは他にも jo とかありますよね?
$ jo -p name=jo n=17 parser=false
{
"name": "jo",
"n": 17,
"parser": false
}
$ jo -p name=jo n=17 parser=false | curl --json @- localhost:8080/api
POST /api HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Content-Type: application/json
Accept: application/json
Content-Length: 52
{
"name": "jo",
"n": 17,
"parser": false
}
PUT でデータをアップロードする (-T)
PUT メソッドでファイルを送信する場合は -T
(--upload-file
) オプションを使います。
$ curl -sSfL -T file.txt localhost:8080/file
PUT /file HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
Content-Length: 5
test
標準入力から読み取る場合は「-」を指定します。この場合 chunk で送信されるようです。
$ curl -sSfL -T - localhost:8080/file < file.txt
PUT /file HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
Transfer-Encoding: chunked
Expect: 100-continue
5
test
0
Content-Type の指定が必要な場合は -H
(--header
) で追加します。JSON ファイルの場合は、次で説明する -X
オプションを使用したほうが簡単かもしれません。
$ curl -sSfL -H 'Content-Type: text/plain' -T file.txt localhost:8080/file
PUT /file HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
Content-Type: text/plain
Content-Length: 5
test
$ curl -sS -X PUT --json @file.json localhost:8080/file.json
PUT /file.json HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Content-Type: application/json
Accept: application/json
Content-Length: 11
{"a": 123}
DELETE メソッドなどを使う (-X)
その他の HTTP メソッドに変更したい場合は -X
(--request
) オプションを使います。
$ curl -X DELETE localhost:8080/file
DELETE /file HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.12.1
Accept: */*
さいごに
はぁーーー、やっと前からアップデートしたかった内容が書けました! HTTP/HTTPS 関連で他になにか便利な curl
の使い方があったら教えてください。