PowerShell: ダブルクォートを`""`でエスケープする際、空白の有無によってエスケープの結果が変わる

2021/09/23に公開約2,300字

動作環境

  • Windows 10
    • PowerShell 5.1.19041.1151
  • Python3.8

やりたいこと

コマンドラインの引数に、JSON文字列を渡したいです。
JSON文字列にはダブルクォートが含まれているので、何らかの対応が必要です。
たとえばbashの場合は、JSON文字列をシングルクォートで括れば、JSON文字列内のダブルクォートをコマンドライン引数に正しく渡すことができます。

サンプルとして、1番目の引数を出力するPythonスクリプトを実行します。

print_arg1.py
import sys
print(sys.argv[1])
$ python print_arg1.py '{"x": 1}'
{"x": 1}

同じようなことを、WindowsのPoerShellでも行いたいです。

問題

以下の記事を流し読みして、「JSON文字列内のダブルクォートをエスケープするには、ダブルクォートを連続で記述すればよい」と解釈しました(正しくない気がする)。。

https://docs.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-7.1

JSON文字列内のダブルクォートを連続で記述して、pythonコマンドを実行しました。

# エスケープされない
PS > python .\print_arg1.py '{"x": 1}'
{x: 1}

# エスケープされた
PS > python .\print_arg1.py '{""x"": 1}'
{"x": 1}

# エスケープされない?!
PS > python .\print_arg1.py '{""x"":1}'
{x:1}

JSON文字列内に空白が存在するとエスケープされ、空白が存在しないとエスケープされませんでした。

原因?

原因は分かりませんでしたが、以下の質問の回答に、関係ありそうな文がありました。

https://stackoverflow.com/a/59681993/9156371

Powershell will auto-quote (enclose in <">) a single argument string, if it contains spaces and the spaces don't mix with an uneven number of (unsescaped) double quotes.

解決方法

ダブルクォートをバックスラッシュでエスケープすることで解決しました。

PS > python .\print_arg1.py '{\"x\":1}'
{"x":1}

https://stackoverflow.com/questions/53490414/how-to-pass-json-string-data-to-powershell 参考

補足

コマンドプロンプトの場合

# ==== JSON文字列をシングルクォートで括る ====

# NG
> python .\print_arg1.py '{"x": 1}'
'{x:

# NG
> python .\print_arg1.py '{""x"": 1}'
'{x:

# NG
> python .\print_arg1.py '{""x"":1}'
'{x:1}'

# NG。
> python .\print_arg1.py '{\"x\":1}'
'{"x":1}'

# NG。JSON文字列内に空白があると、途中までしか表示されない
> python .\print_arg1.py '{\"x\": 1}'
'{"x":

# ==== JSON文字列をダブルクォートで括る ====
# OK
>python .\print_arg1.py "{\"x\": 1}"
{"x": 1}

# OK。JSON文字列内に空白がなくてもエスケープされる
>python .\print_arg1.py "{\"x\":1}"
{"x":1}

# OK
>python .\print_arg1.py "{""x"": 1}"
{"x": 1}

# OK。JSON文字列内に空白がなくてもエスケープされる
>python .\print_arg1.py "{""x"":1}"
{"x":1}

コマンドプロンプトの場合は、ダブルクォートをバックスラッシュまたはダブルクォートでエスケープした上で、JSON文字列をダブルクォートで括る必要があるようです。

PowerShellでJSON文字列をダブルクォートで括った場合

PowerShellの場合はシングルクォートで括るのが正しいのですが、念のためダブルクォートで括ったときの動きも確認します。

PS > python .\print_arg1.py "{"x": 1}"
{

PS > python .\print_arg1.py "{""x"": 1}"
{x: 1}

PS > python .\print_arg1.py "{""x"":1}"
{x:1}

PS > python .\print_arg1.py "{\"x\": 1}"
{\
GitHubで編集を提案

Discussion

ログインするとコメントできます