curl
x-www-form-urlencodeを使用してファイル内でPOST JSONデータを実行しようとしていますdocker-compose
。この例では、このパブリックウェブサイトを使用しており、次のように応答する必要があります。
# sh -c 'curl http://httpbin.org/post -F "json={\"key\": \"value\"}"'
{
"args": {},
"data": "",
"files": {},
"form": {
"json": "{\"key\": \"value\"}"
}, ...
これは外部の一重引用符でうまく機能しますが、内部に変数があるため、二重引用符が必要です。したがって、このコマンドは機能せず、入れ子になった引用符をエスケープする正しい構文を見つけることはできません。
# sh -c "curl http://httpbin.org/post -F "json={\"key\": \"$VAR\"}""
{
"args": {},
"data": "",
"files": {},
"form": {
"json": "{key:"
},
答え1
送信されるパラメータに挿入するデータcurl
は、JSON文書をエンコードするJSONエンコード文字列です。
文字列は次のように別々に生成できます。
json_string=$( jq -n --arg 'my key' 'my "value"' '$ARGS.named|@json' )
JSON認識ツールを使用してjq
データをJSONエンコード文字列に変換することで、文字列の内容が有効なJSON文字列であり、指定されたキー、およびを含むmy key
有効なJSON文書にデコードできることを確認します。値、my "value"
。
上記の正確なコマンドは文字列"{\"my key\":\"my \\\"value\\\"\"}"
をに割り当てますjson_string
。
curl
その後、次のようにパラメータからこの文字列を使用して直接呼び出すことができます。
curl 'http://httpbin.org/post' -F "json=$json_string"
sh -c
...または、次のように文字列をそのスクリプトにパラメータとして渡して、インラインスクリプトから呼び出すことができます。
sh -c 'curl "http://httpbin.org/post" -F "json=$1"' sh "$json_string"
これらの呼び出しの1つは、curl
次の応答を取得します。
{
"args": {},
"data": "",
"files": {},
"form": {
"json": "{\"my key\":\"my \\\"value\\\"\"}"
},
"headers": {
"Accept": "*/*",
"Content-Length": "160",
"Content-Type": "multipart/form-data; boundary=------------------------f805cf070f665e7e",
"Host": "httpbin.org",
"User-Agent": "curl/7.84.0",
"X-Amzn-Trace-Id": "Root=1-83012651-2995681c270059da2906c40f"
},
"json": null,
"origin": "xxx.xxx.xxx.xxx",
"url": "http://httpbin.org/post"
}
JSONドキュメントをJSON文字列にエンコードすることはそれcurl
自体で行われるように見えるので、必ずしも必要ではありません。
json_string=$( jq -n -c --arg 'my key' 'my "value"' '$ARGS.named' )
jo
...JSON文字列を生成するか、インストールした場合は短い文字列を生成します。
json_string=$( jo 'my key'='my "value"' )
答え2
このように?
$ var=hello
$ sh -c "curl http://httpbin.org/post -F 'json={\"key\": \"$var\"}'"
{
"args": {},
"data": "",
"files": {},
"form": {
"json": "{\"key\": \"hello\"}"
},
メモ:
$ sh -c "curl http://httpbin.org/post -F 'json={\"key\": \"$var\"}'"
1 2 3 3 34 3 21
(1)外側二重引用符、(2)一重引用符、いいえ内部二重引用符は特別なので、エスケープする必要はありません。 (3)内部二重引用符は外部二重引用符に対してエスケープされます。 (4)実行する前に、外部二重引用符内に変数拡張を実行しますsh -c
(変数の値に一重引用符がある場合は、内部シェルに問題が発生し、そこに二重引用符がJSON構文を混乱させる可能性があることに注意してください)。
sh
Bashで、を使用して実行すると、次の-x
ように実行されることがわかります。
+ curl http://httpbin.org/post -F 'json={"key": "hello"}'
2 3 3 3 3 2
これは見えるものとほぼ同じですsh -c
。ここで、(2)は引用符付き文字列、(3)は文字列内の特殊でない二重引用符です。
(Dashの出力が明示的ではないため、「Bashで」と言いますset -x
。Bashでは通常、引用された-x
出力を再実行します。たとえば、コマンドを発行すると表示されますが、echo "foo bar"
これecho 'foo bar'
は実際には特別なケースを変更しません。) 。
答え3
Heredocsを使用すると、この引用をより簡単に管理できます。
sh <<END_SCRIPT
curl http://httpbin.org/post -F 'json={"key": "$VAR"}'
END_SCRIPT
Heredoc自体は参照されないため、変数が置き換えられます。
もしVAR="foo bar"
、私達は得る
...
"form": {
"json": "{\"key\": \"foo bar\"}"
},
...
心配する必要があるのは、変数の値に引用符が含まれているかどうかです。
VAR='She said "Hello"'
無効なJSONが表示されます。
...
"form": {
"json": "{\"key\": \"She said \"Hello\"\"}"
},
...
シェルパラメータ拡張を使用して、内部引用符をエスケープできます。
sh <<END_SCRIPT
curl http://httpbin.org/post -F 'json={"key": "${VAR//\"/\\\"}"}'
END_SCRIPT
〜する
...
"form": {
"json": "{\"key\": \"She said \\\"Hello\\\"\"}"
},
...