Pythonでエスケープされた二重引用符(shell = True)がBashと異なるのはなぜですか?

Pythonでエスケープされた二重引用符(shell = True)がBashと異なるのはなぜですか?

echoPythonスクリプトを使用してJSON設定ファイルを作成して呼び出す必要があります。tee

試行錯誤を経て一重引用符を使用しなければならないという事実を知りました。しかし、私はPythonを使用したときに起こるすべての動作を理解していませんrun()。次のコードは私の問題を印刷します。

#!/usr/bin/env python3

from subprocess import run

conf_file="""{
"alt-speed-down": 50,
}"""
print("Question 1. It does not work with double quotes. Why?")
run(f"""echo "{conf_file}" """, shell=True)
print("It works with single quotes.")
run(f"""echo '{conf_file}'""", shell=True)
conf_file="""{
\"alt-speed-down\": 50,
}"""
print("""Question 2. It does not work with double quotes, even when I escape the quotes.
Whereas when I type in my shell: 
echo "\"This is a quoted string.\"" 
it works. Why? 
""")
run(f"""echo "{conf_file}" """, shell=True)
print("""Question 3. It works with single quotes, even with escaped quotes. 
whearas when I type in my shell:
echo '\"this is quoted\"' 
I get the backslashes printed. Why aren't
the backslashes printed when called with Python's run()?""")
run(f"""echo '{conf_file}'""", shell=True)

私はBashをシェルとして使います。 Bashシェルで二重引用符をエスケープするのとPythonで二重引用符をエスケープするのはなぜ違いますか?shell=True仕様を介してBashシェルにアクセスしませんかrun()

PS:モジュールを使用してJSONを作成することがこれを行う1つの方法であることがわかりましたが、json私の場合は、主にバックアップされた設定ファイルから既存のJSONをコピーすることが含まれます。これらのJSONファイルをスクリプトの文字列として読み取ることを避けたいと思います。スクリプトは、最初にそのバックアップが利用できなかった新しく再インストールされたOSで実行するように設計されています。そのため、これらのJSON設定ファイルを保存するには、Python文字列に多くの文字列変数が必要です。

ベストアンサー1

引用符に関して改行を除外すると、次のようになります。

conf_file="""{ "alt-speed-down": 50, }"""

{ "alt-speed-down": 50, }変数に文字列を割り当てます。次に実行すると、run(f"""echo "{conf_file}" """, shell=True)シェルに対応する文字列が表示されます。

echo "{ "alt-speed-down": 50, }"

これは一重引用符とは異なります。

echo '{ "alt-speed-down": 50, }'

conf_file="""{ \"alt-speed-down\": 50, }"""

ここでバックスラッシュは二重引用符をエスケープし、Pythonによって削除されるため、最初のものと同じです。ここでは引用符をエスケープする必要はありませんが、"{ \"alt-speed-down\": 50, }"引用符がある場合はエスケープする必要があります。

Python文字列でバックスラッシュをそのままにするには(または二重引用符と同じr''文字列を使用する必要があります。これは実際に機能し、バックスラッシュは引用符文字列で終わらないようにしても削除されません)r'{ \"alt-speed-down\": 50, }'r"{ \"alt-speed-down\": 50, }"


シェルでは一重引用符内のバックスラッシュが処理されないため、

echo '\"this is quoted\"' 

echo文字列として渡されました\"this is quoted\"。ただし、一部の実装では、シェルのコマンドライン処理で発生した状況に関係なく、echoエスケープ文字(たとえば)を処理します。\n

そして

run(f"""echo '{conf_file}'""", shell=True)

バックスラッシュが見えません。

つまり、シェルとPythonでは引用規則が異なります。

望むより:


コメントで述べたように、PythonでJSON(またはYAMLなど)を生成する方が文字列を手動で印刷するよりも優れています。たとえば、jsonモジュールは次のようになります。

>>> import json
>>> obj = {}
>>> obj["alt-speed-down"] = 50
>>> json.dumps(obj)
'{"alt-speed-down": 50}'

おすすめ記事