为什么 Python 运行中的转义双引号(shell=True)与 Bash 中的不同?

为什么 Python 运行中的转义双引号(shell=True)与 Bash 中的不同?

我需要使用Python 脚本生成echo并调用 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 作为我的 shell。为什么从我的 Bash shell 中转义双引号与 Python 中的转义双引号不同?我是否没有通过shell=Truein指定来访问我的 Bash shell run()

PS 我知道用json模块生成 JSON 是一种方法,但就我而言,它主要是从备份的配置文件中复制现有的 JSON。我想避免将此类 JSON 文件读入脚本中的字符串 - 该脚本旨在在新重新安装的操作系统上运行,此类备份最初不可用。这就是为什么我需要在 Python 字符串中有许多字符串变量来存储此类 JSON 配置文件

答案1

关于引号,撇开换行符不谈,是这样的:

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

将字符串分配{ "alt-speed-down": 50, }给变量。然后当你运行时run(f"""echo "{conf_file}" """, shell=True),shell 会看到该字符串

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, }"实际上也有效,并且反斜杠不会被删除,即使它们被要求不结束带引号的字符串。)


在 shell 中,单引号内的反斜杠不会被处理,所以

echo '\"this is quoted\"' 

传递给echo字符串\"this is quoted\"。尽管 的某些实现echo会处理转义符,例如\n,无论 shell 命令行处理中发生什么。

而与

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

你看不到反斜杠。

简而言之,shell 和 Python 之间的引用规则是不同的。

看:


正如评论中提到的,从 Python 生成 JSON(或 YAML 或其他)可能比手动打印字符串更好。例如json模块:

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

相关内容