[英]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.