bashでのエスケープ文字(JSONの場合)

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で必要な文字をどのようにエスケープすればいいのでしょうか?私はこの言語に詳しくないので、どこから始めればいいのかわかりません。という文字を ' に置き換えることで、最低限のことはできるのではないかと思います。

私もJSONを使った転送のために、Bashで文字をエスケープしようとしていたときに、これに出会いました。特にフリーフォームのテキストを扱おうとしている場合、実際にはもっと大きなエスケープしなければならない文字のリスト – があることを知りました。

私が見つけた便利なTipsは2つあります。

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

その結果、私が思いついた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文字を正しくエスケープする方法はまだ分かっていません。もしこれがわかったら、私の答えを更新します。

解説 (1)
ソリューション

OK、どうすればいいかわかったよ。Bashは予想通りネイティブにサポートしていますが、いつものように構文があまり推測できません

基本的に ${string//substring/replacement} はイメージ通りのものを返すので、以下のように使うことができます。

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

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

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

結局、エスケープする必要すらありませんでした'。JSONの ' を全て &#quot;に置き換えただけです。いやー、毎日勉強になりますね。

解説 (1)

みたいなのを見つけたんだけど.

MSG=`echo $MSG | sed "s/'/\\\\\'/g"`
解説 (2)