74

gitを使用して、コミットメッセージとその他のビットをJSONペイロードとしてサーバーに投稿しています。

現在私は持っています:

MSG=`git log -n 1 --format=oneline | grep -o ' .\+'`

これにより、MSGは次のように設定されます。

Calendar can't go back past today

それから

curl -i -X POST \
  -H 'Accept: application/text' \
  -H 'Content-type: application/json' \
  -d "{'payload': {'message': '$MSG'}}" \
  'https://example.com'

私の実際のJSONには、もう2つのフィールドがあります。

これは正常に機能しますが、もちろん、上記のようなアポストロフィを含むコミットメッセージがある場合、JSONは無効です。

bashで必要な文字をエスケープするにはどうすればよいですか?私はその言語に精通していないので、どこから始めればよいかわかりません。に置き換えることで、少なくとも私はその仕事をするだろうと思います'\'

4

12 に答える 12

75

Pythonの使用:

このソリューションは純粋なbashではありませんが、非侵襲的でユニコードを処理します。

json_escape () {
    printf '%s' "$1" | python -c 'import json,sys; print(json.dumps(sys.stdin.read()))'
}

JSONは標準のPythonライブラリの一部であり、長い間使用されてきたため、これはPythonへの依存関係が非常に少ないことに注意してください。

またはPHPを使用する:

json_escape () {
    printf '%s' "$1" | php -r 'echo json_encode(file_get_contents("php://stdin"));'
}

そのように使用します:

$ json_escape "ヤホー"
"\u30e4\u30db\u30fc"
于 2012-11-20T03:25:55.653 に答える
75

jqこれを行うことができます。

軽量で、無料で、Cで記述されており、 GitHubjqで15,000を超えるスターを使用して、幅広いコミュニティサポートを利用できます。個人的には、日常のワークフローで非常にスピーディーで便利だと感じています。

文字列をJSONに変換する

$ echo '猫に小判' | jq -aRs .
"\u732b\u306b\u5c0f\u5224\n"
$ printf 'ô\nè\nà\n' | jq -Rs .
"ô\nè\nà\n"

説明する、

  • -a「ASCII出力」を意味します(2番目の例では省略)
  • -R「生の入力」を意味します
  • -s「改行を含める」を意味します(ニーモニック:「slurp」)
  • .「JSONドキュメントのルートを出力する」という意味です

Git+Grepのユースケース

OPによって提供されたコード例を修正するには、jqをパイプでつなぐだけです。

MSG=`git log -n 1 --format=oneline | grep -o ' .\+' | jq -aRs .`
于 2018-05-16T22:18:14.260 に答える
59

データを適切に引用する方法を心配する代わりに、データをファイルに保存し、オプションで許可する@構成を使用するだけです。の出力がJSON値として使用するために正しくエスケープされるようにするには、JSONを手動で作成するのではなく、JSONを生成するなどのツールを使用します。curl--datagitjq

jq -n --arg msg "$(git log -n 1 --format=oneline | grep -o ' .\+')" \
   '{payload: { message: $msg }}' > git-tmp.txt

curl -i -X POST \
  -H 'Accept: application/text' \
  -H 'Content-type: application/json' \
  -d @git-tmp.txt \
  'https://example.com'

-d @-;を使用して標準入力から直接読み取ることもできます。これは、読者がから読み取りgit、正しいペイロードメッセージを生成してアップロードするパイプラインを構築するための演習として残しておきますcurl

(ヒント:それはjq ... | curl ... -d@- 'https://example.com'

于 2012-07-15T21:27:18.887 に答える
19

また、これに遭遇したとき、JSONを使用して転送するために、Bashで文字をエスケープしようとしていました。特に自由形式のテキストを処理しようとしている場合は、エスケープする必要のある文字のリストが実際にはもっと多いことがわかりました。

私が役立つと思った2つのヒントがあります。

  • このスレッドで説明されているBash${string//substring/replacement}構文を使用してください。
  • Ctrlタブ、改行、キャリッジリターンなどには、実際の制御文字を使用します。vimでは、 +Vの後に実際の制御コード(たとえば、タブの場合はCtrl+ )を入力して、これらを入力できます。I

私が思いついた結果のBashの置き換えは次のとおりです。

JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\\/\\\\} # \ 
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\//\\\/} # / 
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\'/\\\'} # ' (not strictly needed ?)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\"/\\\"} # " 
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//   /\\t} # \t (tab)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//
/\\\n} # \n (newline)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//^M/\\\r} # \r (carriage return)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//^L/\\\f} # \f (form feed)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//^H/\\\b} # \b (backspace)

私はこの段階では、Unicode文字を正しくエスケープする方法を理解していません。これも(明らかに)必要です。これがうまくいったら、答えを更新します。

于 2012-07-15T20:59:41.650 に答える
15

OK、何をすべきかを見つけました。Bashはこれを期待どおりにネイティブにサポートしますが、いつものように、構文はあまり推測できません。

基本的${string//substring/replacement}にあなたがイメージしたものを返すので、あなたは使うことができます

MSG=${MSG//\'/\\\'}

これをする。次の問題は、最初の正規表現が機能しなくなったことですが、これは次のように置き換えることができます。

git log -n 1 --pretty=format:'%s'

結局、私はそれらを逃れる必要さえありませんでした。代わりに、JSONのすべての'を\ "に交換しました。そうですね、あなたは毎日何かを学びます。

于 2012-04-07T11:10:20.090 に答える
9
git log -n 1 --format=oneline | grep -o ' .\+' | jq --slurp --raw-input

上記の行は私のために働きます。その他のツールについては、 https://github.com/stedolan/jqを参照して くださいjq

于 2016-11-08T06:34:17.253 に答える
4

私はそのようなものを見つけました:

MSG=`echo $MSG | sed "s/'/\\\\\'/g"`
于 2012-04-07T10:34:45.640 に答える
4

最も簡単な方法は、コマンドラインツールであるjshonを使用して、JSONを解析、読み取り、作成することです。

jshon -s 'Your data goes here.' 2>/dev/null

于 2016-02-20T00:28:16.673 に答える
2

[...]アポストロフィが含まれている場合、JSONは無効です。

https://www.json.orgによるとではありません。JSON文字列では一重引用符を使用できます。

bashで必要な文字をエスケープするにはどうすればよいですか?

を使用して、POSTするJSONを適切に準備できます。テストできないので、例として使用します
(この回答を参照https://example.comhttps://api.github.com/markdown

'çömmít' "mêssågè"のエキゾチックな出力として仮定しましょうgit log -n 1 --pretty=format:'%s'

"text"-attributeの値を適切にエスケープして(シリアル化された)JSONオブジェクトを作成します。

$ git log -n 1 --pretty=format:'%s' | \
  xidel -se 'serialize({"text":$raw},{"method":"json","encoding":"us-ascii"})'
{"text":"'\u00E7\u00F6mm\u00EDt' \"m\u00EAss\u00E5g\u00E8\""}

カール(可変)

$ eval "$(
  git log -n 1 --pretty=format:'%s' | \
  xidel -se 'msg:=serialize({"text":$raw},{"method":"json","encoding":"us-ascii"})' --output-format=bash
)"

$ echo $msg
{"text":"'\u00E7\u00F6mm\u00EDt' \"m\u00EAss\u00E5g\u00E8\""}

$ curl -d "$msg" https://api.github.com/markdown
<p>'çömmít' "mêssågè"</p>

カール(パイプ)

$ git log -n 1 --pretty=format:'%s' | \
  xidel -se 'serialize({"text":$raw},{"method":"json","encoding":"us-ascii"})' | \
  curl -d@- https://api.github.com/markdown
<p>'çömmít' "mêssågè"</p>

実際、curlすでにを使用している場合は必要ありませんxidel

Xidel(パイプ)

$ git log -n 1 --pretty=format:'%s' | \
  xidel -s \
  -d '{serialize({"text":read()},{"method":"json","encoding":"us-ascii"})}' \
  "https://api.github.com/markdown" \
  -e '$raw'
<p>'çömmít' "mêssågè"</p>

Xidel(パイプ、クエリ内)

$ git log -n 1 --pretty=format:'%s' | \
  xidel -se '
    x:request({
      "post":serialize(
        {"text":$raw},
        {"method":"json","encoding":"us-ascii"}
      ),
      "url":"https://api.github.com/markdown"
    })/raw
  '
<p>'çömmít' "mêssågè"</p>

Xidel(すべてクエリ内)

$ xidel -se '
  x:request({
    "post":serialize(
      {"text":system("git log -n 1 --pretty=format:'\''%s'\''")},
      {"method":"json","encoding":"us-ascii"}
    ),
    "url":"https://api.github.com/markdown"
  })/raw
'
<p>'çömmít' "mêssågè"</p>
于 2020-03-27T17:10:36.547 に答える
1

私は同じ問題に苦しんでいました。bashでcURLのペイロードに変数を追加しようとしましたが、invalid_JSONとして返され続けました。たくさんのエスケープトリックを試した後、私は自分の問題を解決する簡単な方法に到達しました。答えはすべて一重引用符と二重引用符でした。

 curl --location --request POST 'https://hooks.slack.com/services/test-slack-hook' \
--header 'Content-Type: application/json' \
--data-raw '{"text":'"$data"'}'

多分それは誰かのために重宝します!

于 2020-02-28T12:13:19.907 に答える
0

コミット後にコミットメッセージ付きのメッセージを送信するという同じ考えがありました。最初に私が同じように試したのは、ここでautorと同じでした。しかし、後でより良い、より簡単な解決策を見つけました。

メッセージを送信するphpファイルを作成し、wgetで呼び出します。フック/受信後:

wget -qO - "http://localhost/git.php" 

git.phpで:

chdir("/opt/git/project.git");
$git_log = exec("git log -n 1 --format=oneline | grep -o ' .\+'");

次に、JSONを作成し、PHPスタイルでCURLを呼び出します

于 2017-03-18T14:05:29.193 に答える
0

\これは、バックスラッシュ( )、二重引用符(")、および制御文字U+0000U+001F次のようにエスケープするPerlを使用したエスケープソリューションです。

$ echo -ne "Hello, \n\tBye" | \
  perl -pe 's/(\\(\\\\)*)/$1$1/g; s/(?!\\)(["\x00-\x1f])/sprintf("\\u%04x",ord($1))/eg;'
Hello, \u000a\u0009Bye
于 2017-08-15T00:29:46.400 に答える