![](/img/trans.png)
[英]Python's subprocess.Popen() results differ from command line?
[英]In Python, with subprocess.Popen, is it possible to pass literal quotes to the command to be run, when Popen's command line parameter is in list form?
在 Python 中,使用 subprocess.Popen,当命令及其参数为列表形式时,是否可以将文字引号作为参数传递?
我将进一步解释我的意思。 某些命令可以在其 arguments 中包含文字引号,例如,我正在尝试"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --profile-directory="Profile 1"
有些甚至可能需要它们。
请注意,一个答案指出,从技术上讲,可以从命令行获取 Chrome 以启动任何配置文件,而无需传递文字引号C:\Users\User>"C:\Program Files....\chrome.exe" "--profile-directory=Profile 2"
不过,我问的是传递文字引号,所以"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --profile-directory="Profile 1"
为简单起见,我将使用 calc.exe,因为它在路径中。
import time
import subprocess
proc=subprocess.Popen("calc.exe"+" "+'--profile-directory="Profile 3"')
proc2=subprocess.Popen(["calc.exe",'--profile-directory="Profile 4"'])
time.sleep(3)
proc.wait()
proc2.wait()
现在查看在任务管理器中或通过 wmic 可见的命令行中的差异。
C:\Users\User>wmic process where caption="calc.exe" get commandline | findstr calc c:\windows\system32\calc.exe --profile-directory="Profile 3" c:\windows\system32\calc.exe "--profile-directory=\"Profile 4\"" C:\Users\User>
您可以从 python 解释器中看到这一点
>>> subprocess.Popen(["c:/windows/system32/calc.exe","abc"+'"'+"def"]) ... >>> >>> subprocess.run("C:\Windows\System32\wbem\WMIC.exe process where caption=\"calc.exe\" get commandline") ... c:/windows/system32/calc.exe abc\"def .... >>>
您会看到它在其中粘贴了反斜杠。
关于给出的一些建议的一些评论。
一个建议假设--profile-directory="Profile 1"
与--profile-directory "Profile 1"
相同,即假设您可以将 = 替换为空格,并且 chrome 的工作方式相同。 但事实并非如此。 所以写subprocess.Popen(["C:\...\chrome.exe", "--profile-directory", "Profile 3"])
确实会产生"C:\....\chrome.exe" --profile-directory "Profile 1"
但这不起作用.. 它导致 chrome 要么根本不打开,要么打开一个浏览器 window,它提供了可供单击的配置文件。 等号是必须的。
另一个建议确实
subprocess.Popen(
" ".join(
[
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
'--profile-directory="Person 1"',
]
)
这不是将列表传递给 Popen,而是将列表传递给 join,而 join 将其转换为字符串。
另一个建议是
subprocess.Popen('C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe --profile-directory="Profile 3"')
那是使用字符串。 但是正如您从我的问题中看到的那样,我使用字符串对其进行了管理。 我问的是使用列表。
另一个建议建议"--profile-directory='Profile 1'"
如果我使用 --profile-directory="Profile 1" 运行 chrome,我会得到一个我有时使用的特定配置文件。 但是,如果使用“--profile-directory='Profile 1'”运行 chrome,那么它不会加载该配置文件。 它加载一个空白配置文件。 并且去 chrome://version 显示“'profile 1'”而不是“profile 1”这就像一个不同的配置文件,就像你可能已经说过chrome.exe --profile-directory="profile A"
。 它还会创建以'
开头的目录,如C:\Users\User\AppData\Local\Google\Chrome\User Data\'Profile 1234'
应该删除。
另一个建议建议
subprocess.Popen(
[
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
"--profile-directory=Profile 1",
]
这很有趣,因为它执行"C:\...chrome.exe" "--profile-directory=Profile 1"
它确实使用指定的配置文件加载 chrome。 虽然它不会尝试传递文字引号!
我的问题询问何时传递文字引号。 It's as if maybe it assumes it's a linux shell and inserts a backslash before it, which in a linux would ensure the quote makes it past the shell and to the program being run. 虽然我不确定 go 到 linux shell 上的 ZE206A54E9769086ZEE50CC。 例如,在 Windows 上,如果我在其中粘贴一个 cmd 转义字符,如^
所以“--pro^file-directory=Profile 1”,那么 ^ 就会按字面意思传递。 所以 cmd shell 不会干预。
为什么在 Windows 上,subprocess.Popen 在传递一个列表时调用 list2cmdline,其中(这里是大的“为什么”),然后在字符串中的任何文字双引号中添加一个反斜杠,这意味着当使用将列表传递给 Popen 而不是将字符串传递给它,存在这个问题,您不能传递文字双引号,那么,为什么要添加反斜杠!
我在这里做了一个建议,在 windows 与 linux 中查看 argsv 可能会显示出差异。 我不确定他们是否会实现 C。
我不明白为什么 POpen 在任何情况下都应该表现得像 Windows 需要插入比 Linux 更多的反斜杠。
$ cat ./testargs.py #!/usr/bin/env python3 import sys print(sys.argv) C:\blah>type .\testargsw.py import sys print(sys.argv)
在这两种情况下
C:\blah>.\testargsw.py abc\^"def ['C:\\Users\\User\\testargsw.py', 'abc"def'] >.\testargsw.py abc\"def ['C:\\Users\\User\\testargsw.py', 'abc"def'] C:\blah> $ ./testargs.py abc\"def ['./testargs.py', 'abc"def']
Maybe Windows, specifically the MS C Runtime.. The Code responsible for sending a program's arguments received from the shell, to the main method into argv, is requiring an extra backslash, in a sense because after escaping the double quote, a backslash is then必需的。 (并且 [here] 是由用户输入的)。
话虽如此,但我听说查看 shell 对 Linux 所做的工作基本上是一种误导,因为子进程模块的主要目的是确保您可以完全避免使用 Z2591C98B70119FE62E94898B。
脚本示例可能不那么相关(只是有人建议我检查),但我的问题是 POpen 在传递列表时添加了反斜杠,如 WMIC 输出所示(在命令行列的任务管理器中也可见)。
我和一个长期使用 python 的人交谈过。 他们说子进程是在 2.x 的某个地方添加的,他们仍然使用 os.popen()。 这需要一个字符串而不是一个列表。 已经有人将人们从 os.popen 转移到subprocess.Popen https://docs.python.org/3/library/subprocess.html#replacing-os-popen-os-popen2-os-popen3
Windows 中的 subprocess.Popen 存在问题,它是否具有此列表功能,我认为这很有趣。
简单的解决方法是不使用它的列表功能。 不通过它的列表。 这是一个新功能,没有必要。 你可以给它一个字符串。
该问题包括来自 python 解释器的示例,并显示了(至少在 windows 上),python 如何在文字引号中添加反斜杠。
与我交谈的人向我指出了与此相关的两份文件。
字符串是一个序列。 序列可以是字符串或列表或元组,尽管在本文档中他们使用术语序列仅表示列表或元组,并且当他们说序列时并不表示字符串。
https://peps.python.org/pep-0324/
“类Popen(参数............”
“args 应该是一个字符串,或一系列程序参数”
它提到关于 unix,shell=True 和 shell=False
然后它说“在 Windows 上:Popen class 使用 CreateProcess() 执行子程序,该程序对字符串进行操作。如果 args 是一个序列,它将使用 list2cmdline 方法将其转换为字符串。请注意,并非所有 MS Windows 应用程序以相同的方式解释命令行:list2cmdline 专为使用与 MS C 运行时相同规则的应用程序而设计。”
从技术上讲,字符串是一个序列,但该文档以一种有趣的方式使用了术语序列。 但这意味着在 Windows 上,如果没有给 args 一个字符串,而是给了一个列表或元组,那么它使用 list2cmdline 方法。
一定要使用 print 否则它会使用字符串的 repr()
>>> print(subprocess.list2cmdline(['a', '"b c"'])) a "\"b c\"" >>>
这就是它在幕后使用的 function,在 windows 上,在那里插入一个反斜杠。
我与之交谈的那个人也向我指出了这份文件
https://bugs.python.org/issue11827
一位技术用户评论说,“子进程中的 list2cmdline() 可以公开访问(不以下划线开头),但没有记录。”
这里的重点是,假设他们将 list2cmdline() 设为私有,事实是 Popen 对列表所做的事情,在 Windows 中,以获取命令行,是未记录的。
所以这似乎是一个糟糕的设计,我看不出插入反斜杠的理由。 如果程序员想要插入反斜杠,他们可以这样做。 在我看来,避免将列表传递给 subprocess.POpen 更有意义。
Windows cmd 甚至不使用反斜杠作为转义字符。!!! 它使用插入符号。
C:\Users\User>echo \\
\\
C:\Users\User>echo ^\
\
C:\Users\User>
它是 linux 例如 bash,它使用反斜杠作为转义字符
$ echo \\
\
$
windows 中的某些可执行文件可能需要转义引号并带有反斜杠,但是技术用户可以像技术 linux 用户一样执行此操作。
因此,鉴于他们甚至没有记录“功能”(或错误),他们将如何证明它是合理的,我不知道,但他们可以从记录它开始!
应该做到这一点(如果没有,可能想将shell=True
传递给 Popen ):
subprocess.Popen(["C:\Program Files (x86)\Google\Chrome\Application\chrome.exe", "--profile-directory", "Profile 3"]);
这是可能的,因为--some-flag="some value"
与--some-flag "some value"
相同
ChRomE 解决方案(工作,天哪):
import subprocess
subprocess.Popen(
[
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
"--profile-directory=Profile 1",
]
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.