web-dev-qa-db-ja.com

WindowsでのBashの使用法:「空のメッセージを送信できません」エラー

したがって、Windowsマシンから不一致にいくつかのWebhookを送信する方法が必要です。Linuxで送信することはcurlで問題ありません。そのため、Windows AppsストアからマシンにUbuntu 18 LTSをインストールして、行く。

Windowsで同じコマンドを使用すると、問題が発生します。

bash -c "curl -H "Content-Type:application/json" -X POST -d '{"x": "x", "content": "hello"}' https://discordapp.com/api/webhooks/536660752111763477/zkW73A97-TNJVcH3xMCK0GMHEkwqKNWSfslA0WxxxxxxMYOLTRi6UMXYR_QLDCfxIJ_d"

私はこのエラーを受け取ります:

{"code": 50006, "message": "Cannot send an empty message"}

その文字列でWindowsが嫌いなのは何ですか?

私はスペースやその他のものをいじりましたが、それ以上壊れませんでした。

3
Kieeps

スクリプトの問題は、Ask Ubuntu構文の強調表示によって実際に非常に明確に示されています-回答でわかるように、投稿の"x"は、 -cパラメータの値をbashに。この問題は、コード全体で繰り返されます。

シェルで文字列が機能する方法は、二重引用符が複数の単語(つまり、スペースを含む文字シーケンス)をシェルの単一の単語として表示する方法であるということです。次に、シェルはこれらの単語をそのまま(二重引用符で囲まずに)プログラムに渡して実行します。また、スペースを入れずにテキストをつぶすだけで、テキストを同じWordにまとめることもできます。

したがって、次のコマンドはシェルでもすべて同じで、同じ出力が表示されます。

  • echo 123
  • echo "1"23
  • echo "1"2"3"
  • echo "1"'2'"3"

すべての場合において、echoは「123」というテキスト(単一の引用符で囲んだ最後のもの)を表示するだけで、多くの効果で同じように動作します。

それを念頭に置いて、スクリプト行を分析しましょう。

bash -c "curl -H "Content-Type:application/json" -X POST -d '{"x": "x", "content": "hello"}' https://discordapp.com/some/path"

「実行するコマンド」である-cパラメータとして、多くのコードをbashに渡していることがわかります。したがって、bashは2つの引数で実行されます。最初の引数は-cで、2番目の引数は「コマンド」と見なされるすべてのテキストです。 2番目の引数は、二重引用符で囲まれた文字列(はい、複数形)を使用して、一部のスペースと他のシェル文字をエンコードし、「実行するコマンド」パラメーターにそのまま渡されます。

すべての「単語」を従来のプログラミング言語の文字列配列として変換することにより、シェルが2番目のパラメーターを理解するために手動で実行してみましょう。

var a = [
"-c",
"curl -H " + "Content-Type:application/json" + " -X POST -d '{" + "x" + 
  ": " + "x" + ", " + "content" + ": " + "hello" + 
  "}' https://discordapp.com/some/path"
]

次に、シェルは文字列のリストを解決し、bashを実行します。

execve("bash", "-c", "curl -H Content-Type:application/json -X POST -d '{x: x, content: hello}' https://discordapp.com/some/path");

ご覧のとおり、JSON POSTペイロード内に二重引用符はありません。これらは、2番目の引数を構成する文字列を理解しようとするシェルによって削除されました。これにより、ペイロードが無効になり、入力を提供しなかったと考えるサーバー。

ところで:私の経験から-あなたが示したのは、シェルがエスケープする方法についての1番目の誤解ですので、それについて気を悪くしないでください-みんなそれをやっています;-)

あなたがやりたいこと、二重引用符を入れたい場合inside二重引用符で囲まれた文字列は、それらを「エスケープ」することです-シェルがそれらを特殊文字ではなくテキストの一部として認識しないようにします文字列。これを行うには、主に2つの方法があります。

  1. シェルの文字列は実際には引用符を必要とせず、スペースなしでまとめられた単語、またはスペースなしでまとめられた複数の引用された文字列である可能性があるという事実を利用します。したがって、次のようになります:"curl -H "'"'"Content-Type:application/json"'"'" ..."。二重引用符を置くだけでなく、二重引用符が実際に開始時に開始され、実際には入力の一部ではない文字列を終了し、シェルが入力の終わりを認識する前に、スペース)すぐに新しい文字列を開始します。これは一重引用符で区切られたもので、二重引用符文字のみが含まれます。これは実際、最初の例の最後のechoコマンドと同様です。
  2. バックスラッシュを使用して、内部の二重引用符文字を文字列区切り文字と見なさないようにします-解析からエスケープします:"curl -H \"Content-Type:application/json\" -X...

私は個人的に最初の方法を好みます。

4
Guss