37
36

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

新しい curl コマンドの使い方 完全ガイド(2025年版)

Last updated at Posted at 2025-02-21

はじめに

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 と同じようにどこでも使えるツール兼言語です。

動作確認方法

まず最初にこの記事で使用している動作確認方法について説明します。この記事では 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

この記事を書いた後に思いついたのでこの記事では使っていませんが、こういうのを作ってみました。

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

これらのオプションについては開発者ブログのこちらの記事もどうぞ。

その他のリンクです。

オプションの数

すべてのオプションは 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
指定したURLのファイル名で保存
$ curl -O http://example.com/file.tar.gz

-o オプションを指定しない場合、標準出力に出力されますが、これを出力したくない場合にはファイル名に /dev/null を指定します。

出力を /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 エンコードされます。

クエリー文字列(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: */*
POST でも動作する
$ 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
値は URL エンコードされる
$ 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 . の後ろの . は今は不要です。

HTTPヘッダ以外の情報をJSON形式で出力
$ curl -sS -w '%{json}' -o /dev/null http://example.com | jq
    ︙ 長いので省略
HTTPヘッダの情報をJSON形式で出力
$ 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                                 
通信情報を ASCII で出力
$ 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
                                 ↑
                         他のユーザーに漏洩しています!
他のユーザーから ps コマンド経由で見える
$ 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 やいくつかのネットワークツールなどで使われているパスワードなどを保存するファイルです。

.netrc (パーミッションを600にして他ユーザーから見れなくすること)
machine localhost
login key
password secret
--netrcオプションを指定すれば.netrcに書いたパスワードが送信される
$ 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 オプションで指定します。

config (ファイル名は何でも良い、パーミッションを600にして他ユーザーから見れなくすること)
header = "Authorization: Bearer YourAccessToken"
--netrcオプションを指定すれば.netrcに書いたパスワードが送信される
$ 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 系オプションを併用できない理由は、このように送信形式が異なるためです。filenameContent-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/jsonAccept: 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 のバージョンが古い場合の書き方
$ 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 コマンドを使って書きましょう。別にどんなツールを使っても構いませんが。

JSON は jq で組み立てて curl に流し込めば良い
$ 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 の使い方があったら教えてください。

37
36
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
37
36

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?