curl経由でPOSTリクエストを送信すると二重引用符に問題が発生する

curl経由でPOSTリクエストを送信すると二重引用符に問題が発生する

したがって、POSTリクエストをGist(github)に送信するには、次のようにします。https://gist.github.com/caspyi...

curl --user "user" -X POST --data '{"description":"Created via API","public":"true","files":{"file1.txt":{"content":"Demo"}}' https://api.github.com/gists

しかし、上記の例では、ファイル名とファイルの内容がハードコードされており、その部分が.. file1.txt":{"content":"Demo"}..

私は上記の部分を変数に置き換えています$file":{"content":"$content"}が、変数を初期化しています。JSONリクエストは二重引用符で囲む必要があります。

curl --user "user" -X POST --data "{\"description\":\"Created via API\",\"public\":\"true\",\"files\":{\"$file\":{\"content\":\"$content\"}}' https://api.github.com/gists

しかし、これは機能せず、json エラーが発生します。

{
  "message": "Problems parsing JSON",
  "documentation_url": "https://developer.github.com/v3/gists/#create-a-gist"
}

エスケープされた二重引用符をすべて一重引用符に置き換えた場合でも同じです\'

このJSONリクエスト内に変数を含める方法を誰か知っていますか?ちなみに私は次のようなすべてのヘッダーを使用しました

 -H "Content-Type: application/json; charset=UTF-8" 

リクエストを検証するために多くの組み合わせを試したが、役に立たなかった

アップデート。

全体の内容は次のようになります。

function gist_controller(){
    content=$(cat $1)
    DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
    read -p "enter your password - " pass 
    public="false"
    gist_content=$(cat $1)
    curl --user "samserayo"  -H "Content-Type: application/json; charset=UTF-8" -X POST -d  "{ 'description': 'Created via API', 'public': 'true', 'files':{ ' '$1 ':{ 'content': '$gist_content'}}" https://api.github.com/gists
}
アップデート2

スクリプトが壊れる原因となるファイル(アップロードしようとしているファイル)

<?php echo 'hello world' ?>

答え1

$file または $content に設定した値が表示されません。これらは両方ともどのように展開されますか? どちらか一方、または両方に、JSON パーサーが好まない文字が含まれている可能性があります。おそらく、変数展開値内の何かを、curl を介して JSON パーサーに送信する前に、さらにエスケープまたはエンコードする必要があります。

環境変数をエクスポートしましたか?

試す:

echo "$file $content";

両方が期待どおりに設定されていることを確認します。

答え2

使用しているシェルを指定していませんが、二重引用符で囲まれたものはすべてシェルのファイル名の展開の対象となります。特に、{} はほとんどのシェルで意味を持ちます。引用した例で全体を一重引用符で囲んでいるのはそのためです。

シェル エスケープは扱いにくく、時には望む結果が得られないこともあります。正直なところ、このような場合、シェルが「役に立たない」ことはわかっているので、curl を呼び出す Python スクリプトを作成します。

答え3

これはレビューのために差し戻されたので、別の回答をここに示します。

各部分を個別にエスケープします (最初のエスケープを閉じてから、変数をエスケープします)。

curl --user "user" -X POST --data '{"description":"Created via API","public":"true","files":{"'"${file}"'":{"content":"'"${content}"'"}}}' https://api.github.com/gists

または読みやすくするために分割します:

'{"description":"Created via API","public":"true","files":{"'
"${file}"
'":{"content":"'
"${content}"
'"}}}' 

シェルが変数自体の空白を解釈しないように、内部フィールド区切り文字を変更する必要がある場合もあります。

MWE:cat /tmp/myfile | ./thisscript.sh "myfilename.txt"

#!/bin/sh

FILENAME="${1}"
#CONTENT="$(cat)"
CONTENT="$(sed -e 's/"/\\"/g')" # escape stuff

OFS="${IFS}"
IFS=''

PERSONAL_ACCESS_TOKEN="e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e"

curl --user "username:${PERSONAL_ACCESS_TOKEN}" -X POST --data '{"description":"Created via API","public":"true","files":{"'"${FILENAME}"'":{"content":"'"${CONTENT}"'"}}}' https://api.github.com/gists
IFS="${OFS}"

これを正しく動作させるには、もちろんJSONを壊すすべての文字をエスケープする必要があります。、ファイルの内容には、"制御文字(DOSの改行)などが含まれます。JSON
データ構造を使用することにしたのは残念です。ファイルの内容アップロード。


Gistを作成する別の方法を提案させていただくとすれば、API呼び出しを使用して、たとえば定型文のコンテンツ(空にできない)を含むcurl単一のファイルを作成するだけです。 次に、返されたjson構造をgrepして、README
git_push_urlそしてクローンgist git リポジトリ。その後は、バイナリ データやエスケープの問題を気にせずに、gist に内容を追加するだけgit commitです。git push

答え4

ここに解決策がありますが、2 つのことを前提としています。

は、fileスクリプトに最初の引数として提供されるファイル名です。 は、contentファイルの内容ですtext

また、POST URL がお客様のものとは異なることにもご注意ください (説明は下記を参照)。

#!/bin/bash

file=$1
content=$(cat $1)

curl -H "Content-Type: application/json; charset=UTF-8" -X POST -d  "{ 'description': 'Created via API', 'public': 'true', 'files':{ ' '${file}':{ 'content': '${content}'}}" https://postman-echo.com/post

content.txt ファイルには以下が含まれます:

This is content of the content file.

実行例:

./curl.sh content.txt

出力例:

{
  "args": {},
  "data": "{ 'description': 'Created via API', 'public': 'true', 'files':{ ' 'content.txt ':{ 'content': 'This is content of the content file.'}}",
  "files": {},
  "form": {},
  "headers": {
    "x-forwarded-proto": "https",
    "host": "postman-echo.com",
    "content-length": "134",
    "accept": "*/*",
    "content-type": "application/json; charset=UTF-8",
    "user-agent": "curl/7.65.3",
    "x-forwarded-port": "443"
  },
  "json": null,
  "url": "https://postman-echo.com/post"
}

ノート:

https://postman-echo.com/postここでは、投稿したすべての内容を JSON としてエコーする Web サイトを使用しています。

content.txt ファイルの内容がより複雑な場合、適切にエスケープする必要があるため、このソリューションは機能しない可能性があります。コンテンツは「content」フィールドに入力されるため、json のすべてのエスケープ ルールがここに適用されます。

応答が美しく表示されるようにするには (上記の json のように)、curl の最後に以下を追加します| jq .(最初にインストールする必要がある場合があります)。

https://postman-echo.com/post | jq . 

コンテンツ ファイル全体を自動的に引用するために使用することも可能ですjq(より高度な使用が必要な場合)。

$ jq -Rs '.' content.txt
"This is just a text.\n"

$ jq -Rs '.' content.cpp
"#include <iostream>\nusing namespace std;\nint main() \n{\n    cout << \"Hello, World!\";\n    return 0;\n}\n"

curl.sh動作させるにはスクリプトを少し変更する必要があります:

content=$(jq -Rs '.' $1)

関連情報