subprocess
— 子程序管理¶
原始碼: Lib/subprocess.py
subprocess
模組允許您生成新程序,連線到它們的輸入/輸出/錯誤管道,並獲取它們的返回程式碼。此模組旨在替換一些舊模組和函式
os.system
os.spawn*
有關如何使用 subprocess
模組替換這些模組和函式的資訊可在以下章節中找到。
參見
PEP 324 – 提議 subprocess 模組的 PEP
可用性: 非 Android、非 iOS、非 WASI。
該模組在移動平臺或WebAssembly 平臺上不受支援。
使用 subprocess
模組¶
呼叫子程序的推薦方法是使用 run()
函式處理所有它能處理的用例。對於更高階的用例,可以直接使用底層的 Popen
介面。
- subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, capture_output=False, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None, text=None, env=None, universal_newlines=None, **other_popen_kwargs)¶
執行 args 描述的命令。等待命令完成,然後返回一個
CompletedProcess
例項。上面顯示的引數僅是最常見的引數,將在下面的 常用引數 中描述(因此在縮寫簽名中使用了僅限關鍵字的表示法)。完整的函式簽名與
Popen
建構函式的簽名大致相同——此函式的大多數引數都傳遞給該介面。(timeout、input、check 和 capture_output 除外。)如果 capture_output 為 true,則 stdout 和 stderr 將被捕獲。使用時,內部
Popen
物件會自動建立,其 stdout 和 stderr 都設定為PIPE
。不能同時提供 stdout 和 stderr 引數以及 capture_output。如果您希望捕獲並將兩個流合併為一個,請將 stdout 設定為PIPE
,將 stderr 設定為STDOUT
,而不是使用 capture_output。可以指定以秒為單位的 timeout,它在內部傳遞給
Popen.communicate()
。如果超時,子程序將被殺死並等待。在子程序終止後,TimeoutExpired
異常將被重新引發。在許多平臺 API 上,初始程序建立本身無法中斷,因此您無法保證在程序建立所需時間之前看到超時異常。input 引數傳遞給
Popen.communicate()
,從而傳遞給子程序的標準輸入。如果使用,它必須是位元組序列,如果指定了 encoding 或 errors 或 text 為 true,則必須是字串。使用時,內部Popen
物件會自動建立,其 stdin 設定為PIPE
,並且不能同時使用 stdin 引數。如果 check 為 true,並且程序以非零退出程式碼退出,則將引發
CalledProcessError
異常。該異常的屬性包含引數、退出程式碼以及 stdout 和 stderr(如果它們被捕獲)。如果指定了 encoding 或 errors,或者 text 為 true,則 stdin、stdout 和 stderr 的檔案物件將以文字模式開啟,使用指定的 encoding 和 errors 或
io.TextIOWrapper
預設值。universal_newlines 引數等同於 text,是為了向後相容而提供的。預設情況下,檔案物件以二進位制模式開啟。如果 env 不為
None
,它必須是一個定義新程序環境變數的對映;這些變數用於代替繼承當前程序環境的預設行為。它直接傳遞給Popen
。此對映可以是任意平臺上的字串到字串,或 POSIX 平臺上的位元組到位元組,類似於os.environ
或os.environb
。示例:
>>> subprocess.run(["ls", "-l"]) # doesn't capture output CompletedProcess(args=['ls', '-l'], returncode=0) >>> subprocess.run("exit 1", shell=True, check=True) Traceback (most recent call last): ... subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1 >>> subprocess.run(["ls", "-l", "/dev/null"], capture_output=True) CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0, stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n', stderr=b'')
在 3.5 版本加入。
3.6 版中變更: 添加了 encoding 和 errors 引數
3.7 版中變更: 添加了 text 引數,作為 universal_newlines 更易理解的別名。添加了 capture_output 引數。
3.12 版中變更: 更改了 Windows shell 搜尋順序,針對
shell=True
。當前目錄和%PATH%
被替換為%COMSPEC%
和%SystemRoot%\System32\cmd.exe
。因此,在當前目錄中放置名為cmd.exe
的惡意程式不再有效。
- class subprocess.CompletedProcess¶
run()
的返回值,表示一個已完成的程序。- args¶
用於啟動程序的引數。這可以是一個列表或一個字串。
- returncode¶
子程序的退出狀態。通常,退出狀態為 0 表示它成功執行。
負值
-N
表示子程序被訊號N
終止(僅限 POSIX)。
- stdout¶
從子程序捕獲的 stdout。一個位元組序列,如果呼叫
run()
時帶有編碼、錯誤或 text=True,則為字串。如果未捕獲 stdout,則為None
。如果您使用
stderr=subprocess.STDOUT
執行程序,stdout 和 stderr 將在此屬性中合併,並且stderr
將為None
。
- check_returncode()¶
如果
returncode
不為零,則引發CalledProcessError
。
在 3.5 版本加入。
- subprocess.DEVNULL¶
一個特殊值,可用作
Popen
的 stdin、stdout 或 stderr 引數,表示將使用特殊檔案os.devnull
。在 3.3 版本加入。
- subprocess.PIPE¶
一個特殊值,可用作
Popen
的 stdin、stdout 或 stderr 引數,表示應開啟到標準流的管道。最常與Popen.communicate()
一起使用。
- exception subprocess.SubprocessError¶
此模組中所有其他異常的基類。
在 3.3 版本加入。
- exception subprocess.TimeoutExpired¶
SubprocessError
的子類,在等待子程序時超時時引發。- cmd¶
用於生成子程序的命令。
- timeout¶
超時時間(秒)。
- output¶
如果透過
run()
或check_output()
捕獲,則為子程序的輸出。否則為None
。無論text=True
設定如何,只要捕獲到任何輸出,這始終是bytes
。如果沒有觀察到輸出,它可能保持None
而不是b''
。
- stderr¶
如果透過
run()
捕獲,則為子程序的 stderr 輸出。否則為None
。無論text=True
設定如何,只要捕獲到 stderr 輸出,這始終是bytes
。如果沒有觀察到 stderr 輸出,它可能保持None
而不是b''
。
在 3.3 版本加入。
3.5 版中變更: 添加了 stdout 和 stderr 屬性
- exception subprocess.CalledProcessError¶
SubprocessError
的子類,當由check_call()
、check_output()
或run()
(帶check=True
) 執行的程序返回非零退出狀態時引發。- returncode¶
子程序的退出狀態。如果程序因訊號退出,這將是負訊號數。
- cmd¶
用於生成子程序的命令。
- output¶
如果透過
run()
或check_output()
捕獲,則為子程序的輸出。否則為None
。
3.5 版中變更: 添加了 stdout 和 stderr 屬性
常用引數¶
為了支援各種用例,Popen
建構函式(和便利函式)接受大量可選引數。對於大多數典型用例,許多這些引數可以安全地保留其預設值。最常用的引數是
args 是所有呼叫都必需的,它應該是一個字串或程式引數序列。通常建議提供一個引數序列,因為它允許模組處理任何所需的轉義和引數引用(例如,允許檔名中包含空格)。如果傳遞單個字串,則 shell 必須為
True
(見下文),否則該字串必須只是要執行的程式的名稱,而不指定任何引數。stdin, stdout 和 stderr 分別指定了被執行程式的標準輸入、標準輸出和標準錯誤檔案控制代碼。有效值為
None
,PIPE
,DEVNULL
, 一個現有檔案描述符(正整數), 以及一個具有有效檔案描述符的現有檔案物件。在預設設定為None
的情況下,不會發生重定向。PIPE
表示應該建立一個到子程序的新管道。DEVNULL
表示將使用特殊檔案os.devnull
。此外,stderr 可以是STDOUT
,這表示子程序的 stderr 資料應該捕獲到與 stdout 相同的 檔案控制代碼中。如果指定了 encoding 或 errors,或者 text (也稱為 universal_newlines) 為真,則檔案物件 stdin, stdout 和 stderr 將以文字模式開啟,使用呼叫中指定的 encoding 和 errors,或者
io.TextIOWrapper
的預設值。對於 stdin,輸入中的換行符
'\n'
將轉換為預設的行分隔符os.linesep
。對於 stdout 和 stderr,輸出中的所有換行符都將轉換為'\n'
。更多資訊請參閱io.TextIOWrapper
類的文件,當其建構函式的 newline 引數為None
時。如果未使用文字模式,stdin、stdout 和 stderr 將作為二進位制流開啟。不執行編碼或行尾轉換。
3.6 版中變更: 添加了 encoding 和 errors 引數。
3.7 版中變更: 添加了 text 引數作為 universal_newlines 的別名。
備註
檔案物件
Popen.stdin
、Popen.stdout
和Popen.stderr
的 newlines 屬性不會被Popen.communicate()
方法更新。如果 shell 為
True
,則指定的命令將透過 shell 執行。這在您主要使用 Python 來增強對大多數系統 shell 的控制流,但仍希望方便地訪問其他 shell 功能(如 shell 管道、檔名萬用字元、環境變數擴充套件以及將~
擴充套件到使用者主目錄)時非常有用。但是,請注意 Python 本身提供了許多類似 shell 的功能實現(特別是glob
、fnmatch
、os.walk()
、os.path.expandvars()
、os.path.expanduser()
和shutil
)。3.3 版中變更: 當 universal_newlines 為
True
時,該類使用編碼locale.getpreferredencoding(False)
而不是locale.getpreferredencoding()
。有關此更改的更多資訊,請參閱io.TextIOWrapper
類。備註
在使用
shell=True
之前,請閱讀 安全注意事項 部分。
這些選項,連同所有其他選項,將在 Popen
建構函式文件中更詳細地描述。
Popen 建構函式¶
此模組中的底層程序建立和管理由 Popen
類處理。它提供了很大的靈活性,以便開發人員能夠處理便利函式未涵蓋的罕見情況。
- class subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=None, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *, group=None, extra_groups=None, user=None, umask=-1, encoding=None, errors=None, text=None, pipesize=-1, process_group=None)¶
在一個新程序中執行一個子程式。在 POSIX 上,該類使用類似於
os.execvpe()
的行為來執行子程式。在 Windows 上,該類使用 WindowsCreateProcess()
函式。Popen
的引數如下。args 應該是一個程式引數序列,或者是一個單獨的字串或 類路徑物件。預設情況下,如果 args 是一個序列,要執行的程式是 args 中的第一個項。如果 args 是一個字串,則解釋是平臺相關的,如下所述。有關與預設行為的其他差異,請參閱 shell 和 executable 引數。除非另有說明,建議將 args 作為序列傳遞。
警告
為了獲得最大的可靠性,請為可執行檔案使用完全限定路徑。要在
PATH
上搜索不合格的名稱,請使用shutil.which()
。在所有平臺上,傳遞sys.executable
是再次啟動當前 Python 直譯器並使用-m
命令列格式啟動已安裝模組的推薦方式。解析 executable(或 args 的第一個專案)的路徑是平臺相關的。對於 POSIX,請參閱
os.execvpe()
,並注意在解析或搜尋可執行檔案路徑時,cwd 會覆蓋當前工作目錄,env 可以覆蓋PATH
環境變數。對於 Windows,請參閱 WinAPICreateProcess
的lpApplicationName
和lpCommandLine
引數的文件,並注意在使用shell=False
解析或搜尋可執行檔案路徑時,cwd 不會覆蓋當前工作目錄,env 不能覆蓋PATH
環境變數。使用完整路徑可以避免所有這些變化。將一些引數作為序列傳遞給外部程式的示例是
Popen(["/usr/bin/git", "commit", "-m", "Fixes a bug."])
在 POSIX 上,如果 args 是一個字串,則該字串將被解釋為要執行的程式的名稱或路徑。但是,這隻能在不向程式傳遞引數的情況下完成。
備註
如何將 shell 命令分解為引數序列可能並不明顯,尤其是在複雜情況下。
shlex.split()
可以說明如何確定 args 的正確分詞>>> import shlex, subprocess >>> command_line = input() /bin/vikings -input eggs.txt -output "spam spam.txt" -cmd "echo '$MONEY'" >>> args = shlex.split(command_line) >>> print(args) ['/bin/vikings', '-input', 'eggs.txt', '-output', 'spam spam.txt', '-cmd', "echo '$MONEY'"] >>> p = subprocess.Popen(args) # Success!
特別注意,在 shell 中透過空格分隔的選項(例如 -input)和引數(例如 eggs.txt)會放在不同的列表元素中,而在 shell 中需要引號或反斜槓轉義的引數(例如包含空格的檔名或上面所示的 echo 命令)是單個列表元素。
在 Windows 上,如果 args 是一個序列,它將按照 將引數序列轉換為 Windows 上的字串 中描述的方式轉換為字串。這是因為底層的
CreateProcess()
對字串進行操作。3.6 版中變更: 如果 shell 為
False
且 POSIX 上包含類路徑物件的序列,則 args 引數接受 類路徑物件。3.8 版中變更: 如果 shell 為
False
且 Windows 上包含位元組和類路徑物件的序列,則 args 引數接受 類路徑物件。shell 引數(預設為
False
)指定是否將 shell 用作要執行的程式。如果 shell 為True
,建議將 args 作為字串而不是序列傳遞。在 POSIX 上,如果
shell=True
,shell 預設為/bin/sh
。如果 args 是一個字串,該字串指定透過 shell 執行的命令。這意味著該字串必須與在 shell 提示符下鍵入時完全相同的格式。例如,這包括對包含空格的檔名進行引號或反斜槓轉義。如果 args 是一個序列,第一個專案指定命令字串,任何額外的專案將被視為 shell 本身的額外引數。也就是說,Popen
執行等同於Popen(['/bin/sh', '-c', args[0], args[1], ...])
在 Windows 上,如果
shell=True
,COMSPEC
環境變數指定預設 shell。您只需要在要執行的命令是 shell 的內建命令(例如 dir 或 copy)時才需要在 Windows 上指定shell=True
。您不需要shell=True
來執行批處理檔案或基於控制檯的可執行檔案。備註
在使用
shell=True
之前,請閱讀 安全注意事項 部分。在建立 stdin/stdout/stderr 管道檔案物件時,bufsize 將作為相應的引數提供給
open()
函式0
表示無緩衝(讀寫是一個系統呼叫,可能返回短資料)1
表示行緩衝(僅在text=True
或universal_newlines=True
時可用)任何其他正值表示使用大約該大小的緩衝區
負值 bufsize(預設值)表示將使用系統預設值 io.DEFAULT_BUFFER_SIZE。
3.3.1 版中變更: bufsize 現在預設為 -1,以便預設啟用緩衝,以匹配大多數程式碼期望的行為。在 Python 3.2.4 和 3.3.1 之前的版本中,它錯誤地預設為
0
,即無緩衝並允許短讀。這是無意的,並且與大多數程式碼期望的 Python 2 行為不符。executable 引數指定要執行的替代程式。它很少需要。當
shell=False
時,executable 替換 args 指定的要執行的程式。然而,原始的 args 仍然傳遞給程式。大多數程式將 args 指定的程式視為命令名稱,這可能與實際執行的程式不同。在 POSIX 上,args 名稱成為實用程式(如 ps)中可執行檔案的顯示名稱。如果shell=True
,在 POSIX 上,executable 引數指定預設/bin/sh
的替代 shell。3.6 版中變更: executable 引數在 POSIX 上接受 類路徑物件。
3.8 版中變更: executable 引數在 Windows 上接受位元組和 類路徑物件。
3.12 版中變更: 更改了 Windows shell 搜尋順序,針對
shell=True
。當前目錄和%PATH%
被替換為%COMSPEC%
和%SystemRoot%\System32\cmd.exe
。因此,在當前目錄中放置名為cmd.exe
的惡意程式不再有效。stdin、stdout 和 stderr 分別指定了被執行程式的標準輸入、標準輸出和標準錯誤檔案控制代碼。有效值為
None
、PIPE
、DEVNULL
、一個現有檔案描述符(正整數)以及一個具有有效檔案描述符的現有檔案物件。在預設設定為None
的情況下,不會發生重定向。PIPE
表示應該建立一個到子程序的新管道。DEVNULL
表示將使用特殊檔案os.devnull
。此外,stderr 可以是STDOUT
,這表示應用程式的 stderr 資料應該捕獲到與 stdout 相同的 檔案控制代碼中。如果 preexec_fn 設定為一個可呼叫物件,則該物件將在子程序執行之前在子程序中呼叫。(僅限 POSIX)
警告
在應用程式中存線上程的情況下,preexec_fn 引數使用不安全。在呼叫 exec 之前,子程序可能會死鎖。
備註
如果您需要修改子程序的環境,請使用 env 引數,而不是在 preexec_fn 中進行。start_new_session 和 process_group 引數應該取代使用 preexec_fn 在子程序中呼叫
os.setsid()
或os.setpgid()
的程式碼。3.8 版中變更: 子直譯器不再支援 preexec_fn 引數。在子直譯器中使用該引數會引發
RuntimeError
。新的限制可能會影響部署在 mod_wsgi、uWSGI 和其他嵌入式環境中的應用程式。如果 close_fds 為 true,則除
0
、1
和2
之外的所有檔案描述符都將在子程序執行之前關閉。否則,當 close_fds 為 false 時,檔案描述符將遵循 檔案描述符的繼承 中所述的其可繼承標誌。在 Windows 上,如果 close_fds 為 true,則子程序不會繼承任何控制代碼,除非在
STARTUPINFO.lpAttributeList
的handle_list
元素中明確傳遞,或透過標準控制代碼重定向。3.2 版中變更: close_fds 的預設值已從
False
更改為上面描述的值。3.7 版中變更: 在 Windows 上,當重定向標準控制代碼時,close_fds 的預設值從
False
更改為True
。現在,當重定向標準控制代碼時,可以將 close_fds 設定為True
。pass_fds 是一個可選的檔案描述符序列,用於在父程序和子程序之間保持開啟。提供任何 pass_fds 會強制 close_fds 為
True
。(僅限 POSIX)3.2 版中變更: 添加了 pass_fds 引數。
如果 cwd 不為
None
,則函式在執行子程序之前將工作目錄更改為 cwd。cwd 可以是字串、位元組或 類路徑 物件。在 POSIX 上,如果可執行檔案路徑是相對路徑,則函式會相對於 cwd 查詢 executable(或 args 中的第一個專案)。3.6 版中變更: cwd 引數在 POSIX 上接受 類路徑物件。
3.7 版中變更: cwd 引數在 Windows 上接受 類路徑物件。
3.8 版中變更: cwd 引數在 Windows 上接受位元組物件。
如果 restore_signals 為 true(預設值),則在子程序執行之前,Python 設定為 SIG_IGN 的所有訊號都將在子程序中恢復為 SIG_DFL。目前這包括 SIGPIPE、SIGXFZ 和 SIGXFSZ 訊號。(僅限 POSIX)
3.2 版中變更: 添加了 restore_signals。
如果 start_new_session 為 true,則在子程序執行之前,將在子程序中進行
setsid()
系統呼叫。可用性:POSIX
3.2 版中變更: 添加了 start_new_session。
如果 process_group 是一個非負整數,則在子程序執行之前,將在子程序中進行
setpgid(0, value)
系統呼叫。可用性:POSIX
3.11 版中變更: 添加了 process_group。
如果 group 不為
None
,則在子程序執行之前,將在子程序中進行 setregid() 系統呼叫。如果提供的值是字串,它將透過grp.getgrnam()
查詢,並使用gr_gid
中的值。如果該值為整數,它將按原樣傳遞。(僅限 POSIX)可用性:POSIX
在 3.9 版本中新增。
如果 extra_groups 不為
None
,則在子程序執行之前,將在子程序中進行 setgroups() 系統呼叫。extra_groups 中提供的字串將透過grp.getgrnam()
查詢,並使用gr_gid
中的值。整數值將按原樣傳遞。(僅限 POSIX)可用性:POSIX
在 3.9 版本中新增。
如果 user 不為
None
,則在子程序執行之前,將在子程序中進行 setreuid() 系統呼叫。如果提供的值是字串,它將透過pwd.getpwnam()
查詢,並使用pw_uid
中的值。如果該值為整數,它將按原樣傳遞。(僅限 POSIX)可用性:POSIX
在 3.9 版本中新增。
如果 umask 不為負數,則在子程序執行之前,將在子程序中進行 umask() 系統呼叫。
可用性:POSIX
在 3.9 版本中新增。
如果 env 不為
None
,它必須是一個定義新程序環境變數的對映;這些變數用於代替繼承當前程序環境的預設行為。此對映可以是任意平臺上的字串到字串,或 POSIX 平臺上的位元組到位元組,類似於os.environ
或os.environb
。備註
如果指定了 env,則 env 必須提供程式執行所需的所有變數。在 Windows 上,為了執行 並行程式集,指定的 env 必須 包含一個有效的
%SystemRoot%
。如果指定了 encoding 或 errors,或者 text 為 true,則檔案物件 stdin、stdout 和 stderr 將以文字模式開啟,並使用指定的 encoding 和 errors,如上文 常用引數 中所述。universal_newlines 引數等同於 text,是為了向後相容而提供的。預設情況下,檔案物件以二進位制模式開啟。
3.6 版新增: 添加了 encoding 和 errors。
3.7 版新增: 添加了 text 作為 universal_newlines 的更具可讀性的別名。
如果提供了 startupinfo,它將是一個
STARTUPINFO
物件,該物件將傳遞給底層的CreateProcess
函式。如果給定 creationflags,它可以是以下一個或多個標誌
當 stdin、stdout 或 stderr 使用
PIPE
時,可以使用 pipesize 來更改管道的大小。管道的大小隻會在支援此功能的平臺(目前僅限 Linux)上更改。其他平臺將忽略此引數。3.10 版中變更: 添加了 pipesize 引數。
Popen 物件透過
with
語句支援上下文管理器:退出時,標準檔案描述符關閉,並等待程序。with Popen(["ifconfig"], stdout=PIPE) as proc: log.write(proc.stdout.read())
Popen 以及此模組中其他使用它的函式會引發一個 審計事件
subprocess.Popen
,其引數為executable
、args
、cwd
和env
。args
的值可能是一個字串或一個字串列表,具體取決於平臺。3.2 版中變更: 增加了上下文管理器支援。
3.6 版中變更: 如果子程序仍在執行,Popen 解構函式現在會發出
ResourceWarning
警告。3.8 版中變更: Popen 在某些情況下可以使用
os.posix_spawn()
以提高效能。在適用於 Linux 的 Windows 子系統和 QEMU 使用者模擬中,使用os.posix_spawn()
的 Popen 建構函式不再在程式丟失等錯誤時引發異常,但子程序會以非零returncode
失敗。
異常¶
在子程序中,在新程式開始執行之前引發的異常,將在父程序中重新引發。
最常見的異常是 OSError
。例如,在嘗試執行不存在的檔案時會發生這種情況。應用程式應該為 OSError
異常做好準備。請注意,當 shell=True
時,OSError
將僅在找不到選定的 shell 本身時由子程序引發。要確定 shell 是否未能找到請求的應用程式,需要檢查子程序的返回程式碼或輸出。
如果使用無效引數呼叫 Popen
,將引發 ValueError
。
check_call()
和 check_output()
將在被呼叫的程序返回非零返回程式碼時引發 CalledProcessError
。
所有接受 timeout 引數的函式和方法,例如 run()
和 Popen.communicate()
,如果超時時間在程序退出之前到期,將引發 TimeoutExpired
。
此模組中定義的所有異常都繼承自 SubprocessError
。
3.3 版新增: 添加了 SubprocessError
基類。
安全考慮¶
與某些其他 popen 函式不同,此庫不會隱式選擇呼叫系統 shell。這意味著所有字元,包括 shell 元字元,都可以安全地傳遞給子程序。如果透過 shell=True
顯式呼叫 shell,則應用程式有責任確保所有空格和元字元都被正確引用,以避免 shell 注入 漏洞。在 某些平臺 上,可以使用 shlex.quote()
進行此轉義。
在 Windows 上,批處理檔案 (*.bat
或 *.cmd
) 可能會被作業系統在系統 shell 中啟動,而不管傳遞給此庫的引數。這可能導致引數根據 shell 規則進行解析,但沒有 Python 新增任何轉義。如果您有意從不受信任的源啟動帶引數的批處理檔案,請考慮傳遞 shell=True
以允許 Python 轉義特殊字元。有關更多討論,請參閱 gh-114539。
Popen 物件¶
Popen
類的例項具有以下方法
- Popen.poll()¶
檢查子程序是否已終止。設定並返回
returncode
屬性。否則,返回None
。
- Popen.wait(timeout=None)¶
等待子程序終止。設定並返回
returncode
屬性。如果程序在 timeout 秒後仍未終止,則引發
TimeoutExpired
異常。捕獲此異常並重試等待是安全的。備註
當使用
stdout=PIPE
或stderr=PIPE
且子程序向管道生成足夠的輸出導致其阻塞等待作業系統管道緩衝區接受更多資料時,這將導致死鎖。在使用管道時使用Popen.communicate()
可避免這種情況。備註
當
timeout
引數不為None
時,(在 POSIX 上)該函式透過忙迴圈(非阻塞呼叫和短睡眠)實現。使用asyncio
模組進行非同步等待:請參閱asyncio.create_subprocess_exec
。3.3 版中變更: 添加了 timeout。
- Popen.communicate(input=None, timeout=None)¶
與程序互動:向 stdin 傳送資料。從 stdout 和 stderr 讀取資料,直到達到檔案末尾。等待程序終止並設定
returncode
屬性。可選的 input 引數應該是要傳送給子程序的資料,如果不需要傳送資料給子程序,則為None
。如果流以文字模式開啟,則 input 必須是字串。否則,它必須是位元組。communicate()
返回一個元組(stdout_data, stderr_data)
。如果流以文字模式開啟,則資料將是字串;否則為位元組。請注意,如果要向程序的 stdin 傳送資料,則需要使用
stdin=PIPE
建立 Popen 物件。同樣,要在結果元組中獲得None
以外的任何內容,您還需要提供stdout=PIPE
和/或stderr=PIPE
。如果程序在 timeout 秒後仍未終止,將引發
TimeoutExpired
異常。捕獲此異常並重試通訊不會丟失任何輸出。如果超時,子程序不會被殺死,因此為了正確清理,行為良好的應用程式應殺死子程序並完成通訊
proc = subprocess.Popen(...) try: outs, errs = proc.communicate(timeout=15) except TimeoutExpired: proc.kill() outs, errs = proc.communicate()
備註
讀取的資料在記憶體中緩衝,因此如果資料大小較大或無限,請勿使用此方法。
3.3 版中變更: 添加了 timeout。
- Popen.send_signal(signal)¶
向子程序傳送訊號 signal。
如果程序已完成,則不執行任何操作。
備註
在 Windows 上,SIGTERM 是
terminate()
的別名。CTRL_C_EVENT 和 CTRL_BREAK_EVENT 可以傳送給使用包含CREATE_NEW_PROCESS_GROUP
的 creationflags 引數啟動的程序。
- Popen.terminate()¶
終止子程序。在 POSIX 作業系統上,該方法向子程序傳送
SIGTERM
。在 Windows 上,呼叫 Win32 API 函式TerminateProcess()
來終止子程序。
- Popen.kill()¶
殺死子程序。在 POSIX 作業系統上,該函式向子程序傳送 SIGKILL。在 Windows 上,
kill()
是terminate()
的別名。
該類還會為您設定以下屬性以供訪問。不支援將它們重新分配給新值
- Popen.stdin¶
如果 stdin 引數是
PIPE
,則此屬性是一個可寫入的流物件,由open()
返回。如果指定了 encoding 或 errors 引數,或者 text 或 universal_newlines 引數為True
,則該流是文字流,否則是位元組流。如果 stdin 引數不是PIPE
,則此屬性為None
。
- Popen.stdout¶
如果 stdout 引數是
PIPE
,則此屬性是一個可讀的流物件,由open()
返回。從該流讀取將提供子程序的輸出。如果指定了 encoding 或 errors 引數,或者 text 或 universal_newlines 引數為True
,則該流是文字流,否則是位元組流。如果 stdout 引數不是PIPE
,則此屬性為None
。
- Popen.stderr¶
如果 stderr 引數是
PIPE
,則此屬性是一個可讀的流物件,由open()
返回。從該流讀取將提供子程序的錯誤輸出。如果指定了 encoding 或 errors 引數,或者 text 或 universal_newlines 引數為True
,則該流是文字流,否則是位元組流。如果 stderr 引數不是PIPE
,則此屬性為None
。
警告
請使用 communicate()
而不是 .stdin.write
、.stdout.read
或 .stderr.read
,以避免由於任何其他作業系統管道緩衝區填滿並阻塞子程序而導致的死鎖。
- Popen.pid¶
子程序的程序 ID。
請注意,如果將 shell 引數設定為
True
,則這是啟動的 shell 的程序 ID。
- Popen.returncode¶
子程序的返回程式碼。最初為
None
,如果在呼叫poll()
、wait()
或communicate()
方法時檢測到程序已終止,則returncode
會被設定。值為
None
表示在上次方法呼叫時程序尚未終止。負值
-N
表示子程序被訊號N
終止(僅限 POSIX)。
Windows Popen 助手¶
STARTUPINFO
類和以下常量僅在 Windows 上可用。
- class subprocess.STARTUPINFO(*, dwFlags=0, hStdInput=None, hStdOutput=None, hStdError=None, wShowWindow=0, lpAttributeList=None)¶
Windows STARTUPINFO 結構的部分支援用於
Popen
建立。可以透過將它們作為僅關鍵字引數傳遞來設定以下屬性。3.7 版本中已更改: 增加了僅關鍵字引數支援。
- dwFlags¶
一個位欄位,它決定在程序建立視窗時是否使用某些
STARTUPINFO
屬性。si = subprocess.STARTUPINFO() si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW
- hStdInput¶
如果
dwFlags
指定STARTF_USESTDHANDLES
,則此屬性是程序的標準輸入控制代碼。如果未指定STARTF_USESTDHANDLES
,則標準輸入的預設值為鍵盤緩衝區。
- hStdOutput¶
如果
dwFlags
指定STARTF_USESTDHANDLES
,則此屬性是程序的標準輸出控制代碼。否則,此屬性將被忽略,標準輸出的預設值為控制檯視窗的緩衝區。
- hStdError¶
如果
dwFlags
指定STARTF_USESTDHANDLES
,則此屬性是程序的標準錯誤控制代碼。否則,此屬性將被忽略,標準錯誤的預設值為控制檯視窗的緩衝區。
- wShowWindow¶
如果
dwFlags
指定STARTF_USESHOWWINDOW
,則此屬性可以是 ShowWindow 函式的nCmdShow
引數中可以指定的任何值,但SW_SHOWDEFAULT
除外。否則,此屬性將被忽略。
- lpAttributeList¶
一個字典,包含
STARTUPINFOEX
中給出的其他程序建立屬性,請參閱 UpdateProcThreadAttribute。支援的屬性
- handle_list
將繼承的控制代碼序列。如果非空,則 close_fds 必須為 True。
當傳遞給
Popen
建構函式時,控制代碼必須透過os.set_handle_inheritable()
暫時設定為可繼承,否則將引發OSError
,錯誤程式碼為 Windows 錯誤ERROR_INVALID_PARAMETER
(87)。警告
在多執行緒程序中,將此功能與併發呼叫其他繼承所有控制代碼的程序建立函式(例如
os.system()
)結合使用時,請謹慎操作,以避免標記為可繼承的控制代碼洩漏。這同樣適用於標準控制代碼重定向,它會暫時建立可繼承的控制代碼。
在 3.7 版本加入。
Windows 常量¶
subprocess
模組公開了以下常量。
- subprocess.STD_INPUT_HANDLE¶
標準輸入裝置。最初,它是控制檯輸入緩衝區,
CONIN$
。
- subprocess.STD_OUTPUT_HANDLE¶
標準輸出裝置。最初,它是活動控制檯螢幕緩衝區,
CONOUT$
。
- subprocess.STD_ERROR_HANDLE¶
標準錯誤裝置。最初,它是活動控制檯螢幕緩衝區,
CONOUT$
。
- subprocess.SW_HIDE¶
隱藏視窗。另一個視窗將被啟用。
- subprocess.STARTF_USESTDHANDLES¶
指定
STARTUPINFO.hStdInput
、STARTUPINFO.hStdOutput
和STARTUPINFO.hStdError
屬性包含額外資訊。
- subprocess.STARTF_USESHOWWINDOW¶
指定
STARTUPINFO.wShowWindow
屬性包含額外資訊。
- subprocess.STARTF_FORCEONFEEDBACK¶
一個
STARTUPINFO.dwFlags
引數,用於指定在程序啟動時將顯示“後臺工作”滑鼠游標。這是 GUI 程序的預設行為。在 3.13 版本加入。
- subprocess.STARTF_FORCEOFFFEEDBACK¶
一個
STARTUPINFO.dwFlags
引數,用於指定在啟動程序時滑鼠游標不會更改。在 3.13 版本加入。
- subprocess.CREATE_NEW_CONSOLE¶
新程序擁有一個新的控制檯,而不是繼承其父程序的控制檯(預設)。
- subprocess.CREATE_NEW_PROCESS_GROUP¶
一個
Popen
creationflags
引數,用於指定將建立一個新的程序組。此標誌對於對子程序使用os.kill()
是必需的。如果指定了
CREATE_NEW_CONSOLE
,則此標誌將被忽略。
- subprocess.REALTIME_PRIORITY_CLASS¶
一個
Popen
creationflags
引數,用於指定新程序將具有即時優先順序。幾乎不應使用 REALTIME_PRIORITY_CLASS,因為它會中斷管理滑鼠輸入、鍵盤輸入和後臺磁碟重新整理的系統執行緒。此類別可能適用於直接與硬體“對話”或執行應受有限中斷的短暫任務的應用程式。在 3.7 版本加入。
- subprocess.DETACHED_PROCESS¶
一個
Popen
creationflags
引數,用於指定新程序不會繼承其父程序的控制檯。此值不能與 CREATE_NEW_CONSOLE 一起使用。在 3.7 版本加入。
舊版高階 API¶
在 Python 3.5 之前,這三個函式構成了 subprocess 的高階 API。現在在許多情況下可以使用 run()
,但許多現有程式碼仍然呼叫這些函式。
- subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None, **other_popen_kwargs)¶
執行 args 描述的命令。等待命令完成,然後返回
returncode
屬性。需要捕獲 stdout 或 stderr 的程式碼應改用
run()
run(...).returncode
要抑制 stdout 或 stderr,請提供
DEVNULL
值。上面顯示的引數只是一些常見的引數。完整的函式簽名與
Popen
建構函式的簽名相同 - 此函式將所有提供的引數(除了 timeout)直接傳遞給該介面。備註
請勿在此函式中使用
stdout=PIPE
或stderr=PIPE
。如果子程序向管道生成足夠的輸出以填滿作業系統管道緩衝區,則子程序將阻塞,因為管道沒有被讀取。3.3 版中變更: 添加了 timeout。
3.12 版中變更: 更改了 Windows shell 搜尋順序,針對
shell=True
。當前目錄和%PATH%
被替換為%COMSPEC%
和%SystemRoot%\System32\cmd.exe
。因此,在當前目錄中放置名為cmd.exe
的惡意程式不再有效。
- subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None, **other_popen_kwargs)¶
使用引數執行命令。等待命令完成。如果返回程式碼為零則返回,否則引發
CalledProcessError
。CalledProcessError
物件將在returncode
屬性中包含返回程式碼。如果check_call()
無法啟動程序,它將傳播引發的異常。需要捕獲 stdout 或 stderr 的程式碼應改用
run()
run(..., check=True)
要抑制 stdout 或 stderr,請提供
DEVNULL
值。上面顯示的引數只是一些常見的引數。完整的函式簽名與
Popen
建構函式的簽名相同 - 此函式將所有提供的引數(除了 timeout)直接傳遞給該介面。備註
請勿在此函式中使用
stdout=PIPE
或stderr=PIPE
。如果子程序向管道生成足夠的輸出以填滿作業系統管道緩衝區,則子程序將阻塞,因為管道沒有被讀取。3.3 版中變更: 添加了 timeout。
3.12 版中變更: 更改了 Windows shell 搜尋順序,針對
shell=True
。當前目錄和%PATH%
被替換為%COMSPEC%
和%SystemRoot%\System32\cmd.exe
。因此,在當前目錄中放置名為cmd.exe
的惡意程式不再有效。
- subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, cwd=None, encoding=None, errors=None, universal_newlines=None, timeout=None, text=None, **other_popen_kwargs)¶
執行帶有引數的命令並返回其輸出。
如果返回程式碼非零,它將引發
CalledProcessError
。CalledProcessError
物件將在returncode
屬性中包含返回程式碼,並在output
屬性中包含任何輸出。這等價於:
run(..., check=True, stdout=PIPE).stdout
上面顯示的引數只是一些常見的引數。完整的函式簽名與
run()
的大致相同——大多數引數直接傳遞給該介面。與run()
行為的一個 API 差異是:傳遞input=None
的行為與input=b''
(或input=''
,取決於其他引數)相同,而不是使用父程序的標準輸入檔案控制代碼。預設情況下,此函式將以編碼位元組的形式返回資料。輸出資料的實際編碼可能取決於所呼叫的命令,因此通常需要在應用程式級別處理文字解碼。
透過將 text、encoding、errors 或 universal_newlines 設定為
True
可以覆蓋此行為,如 常用引數 和run()
中所述。要同時捕獲標準錯誤到結果中,請使用
stderr=subprocess.STDOUT
>>> subprocess.check_output( ... "ls non_existent_file; exit 0", ... stderr=subprocess.STDOUT, ... shell=True) 'ls: non_existent_file: No such file or directory\n'
在 3.1 版本加入。
3.3 版中變更: 添加了 timeout。
3.4 版本中已更改: 增加了對 input 關鍵字引數的支援。
3.6 版本中已更改: 增加了 encoding 和 errors。有關詳細資訊,請參見
run()
。3.7 版新增: 添加了 text 作為 universal_newlines 的更具可讀性的別名。
3.12 版中變更: 更改了 Windows shell 搜尋順序,針對
shell=True
。當前目錄和%PATH%
被替換為%COMSPEC%
和%SystemRoot%\System32\cmd.exe
。因此,在當前目錄中放置名為cmd.exe
的惡意程式不再有效。
使用 subprocess
模組替換舊函式¶
在本節中,“a 變為 b”表示 b 可以用作 a 的替代品。
備註
本節中所有“a”函式在找不到已執行程式時會(或多或少)靜默失敗;“b”替代品會改為引發 OSError
。
此外,使用 check_output()
的替換將因 CalledProcessError
而失敗,如果請求的操作產生非零返回程式碼。輸出仍然作為引發異常的 output
屬性可用。
在以下示例中,我們假設相關函式已從 subprocess
模組中匯入。
替換 /bin/sh shell 命令替換¶
output=$(mycmd myarg)
變為
output = check_output(["mycmd", "myarg"])
替換 shell 管道¶
output=$(dmesg | grep hda)
變為
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits.
output = p2.communicate()[0]
在啟動 p2 後呼叫 p1.stdout.close()
很重要,以便在 p2 在 p1 之前退出時 p1 接收到 SIGPIPE。
或者,對於可信輸入,shell 自己的管道支援仍然可以直接使用
output=$(dmesg | grep hda)
變為
output = check_output("dmesg | grep hda", shell=True)
替換 os.system()
¶
sts = os.system("mycmd" + " myarg")
# becomes
retcode = call("mycmd" + " myarg", shell=True)
備註
通常不需要透過 shell 呼叫程式。
call()
的返回值與os.system()
的返回值編碼方式不同。os.system()
函式在命令執行時忽略 SIGINT 和 SIGQUIT 訊號,但使用subprocess
模組時,呼叫者必須單獨執行此操作。
一個更實際的例子會是這樣
try:
retcode = call("mycmd" + " myarg", shell=True)
if retcode < 0:
print("Child was terminated by signal", -retcode, file=sys.stderr)
else:
print("Child returned", retcode, file=sys.stderr)
except OSError as e:
print("Execution failed:", e, file=sys.stderr)
替換 os.spawn
家族¶
P_NOWAIT 示例
pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg")
==>
pid = Popen(["/bin/mycmd", "myarg"]).pid
P_WAIT 示例
retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg")
==>
retcode = call(["/bin/mycmd", "myarg"])
向量示例
os.spawnvp(os.P_NOWAIT, path, args)
==>
Popen([path] + args[1:])
環境示例
os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env)
==>
Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"})
替換 os.popen()
¶
返回程式碼處理轉換如下
pipe = os.popen(cmd, 'w')
...
rc = pipe.close()
if rc is not None and rc >> 8:
print("There were some errors")
==>
process = Popen(cmd, stdin=PIPE)
...
process.stdin.close()
if process.wait() != 0:
print("There were some errors")
舊版 Shell 呼叫函式¶
此模組還提供了來自 2.x commands
模組的以下舊版函式。這些操作隱式呼叫系統 shell,並且上述關於安全性和異常處理一致性的任何保證對這些函式均無效。
- subprocess.getstatusoutput(cmd, *, encoding=None, errors=None)¶
在 shell 中執行 cmd 並返回
(exitcode, output)
。使用
check_output()
在 shell 中執行字串 cmd,並返回一個 2 元組(exitcode, output)
。encoding 和 errors 用於解碼輸出;有關詳細資訊,請參閱 常用引數 中的註釋。輸出中的尾部換行符將被去除。命令的退出碼可以解釋為 subprocess 的返回碼。示例
>>> subprocess.getstatusoutput('ls /bin/ls') (0, '/bin/ls') >>> subprocess.getstatusoutput('cat /bin/junk') (1, 'cat: /bin/junk: No such file or directory') >>> subprocess.getstatusoutput('/bin/junk') (127, 'sh: /bin/junk: not found') >>> subprocess.getstatusoutput('/bin/kill $$') (-15, '')
可用性: Unix, Windows。
3.3.4 版本中已更改: 增加了對 Windows 的支援。
該函式現在返回 (exitcode, output),而不是像 Python 3.3.3 及更早版本那樣返回 (status, output)。exitcode 具有與
returncode
相同的值。3.11 版本中已更改: 增加了 encoding 和 errors 引數。
- subprocess.getoutput(cmd, *, encoding=None, errors=None)¶
在 shell 中執行 cmd 並返回其輸出(stdout 和 stderr)。
與
getstatusoutput()
類似,只是忽略退出碼,返回值為包含命令輸出的字串。示例>>> subprocess.getoutput('ls /bin/ls') '/bin/ls'
可用性: Unix, Windows。
3.3.4 版本中已更改: 增加了對 Windows 的支援
3.11 版本中已更改: 增加了 encoding 和 errors 引數。
註釋¶
超時行為¶
在使用 run()
、Popen.wait()
或 Popen.communicate()
等函式中的 timeout
引數時,使用者應注意以下行為:
程序建立延遲:在許多平臺 API 上,初始程序建立本身無法中斷。這意味著即使指定了超時,也無法保證在程序建立所需時間之後才能看到超時異常。
極小的超時值:設定非常小的超時值(例如幾毫秒)可能會導致幾乎立即出現
TimeoutExpired
異常,因為程序建立和系統排程本身需要時間。
在 Windows 上將引數序列轉換為字串¶
在 Windows 上,args 序列被轉換為一個字串,可以使用以下規則進行解析(這些規則對應於 MS C 執行時使用的規則)
引數由空白符(空格或製表符)分隔。
用雙引號括起來的字串被解釋為單個引數,無論其中包含多少空白符。帶引號的字串可以嵌入到引數中。
前面帶反斜槓的雙引號被解釋為字面雙引號。
反斜槓被解釋為字面字元,除非它們緊跟在雙引號之前。
如果反斜槓緊跟在雙引號之前,每對反斜槓都被解釋為字面反斜槓。如果反斜槓的數量是奇數,則最後一個反斜槓會轉義下一個雙引號,如規則 3 中所述。
參見
shlex
提供用於解析和轉義命令列功能的模組。
停用 posix_spawn()
的使用¶
在 Linux 上,subprocess
預設情況下在安全的情況下內部使用 vfork()
系統呼叫而不是 fork()
。這大大提高了效能。
subprocess._USE_POSIX_SPAWN = False # See CPython issue gh-NNNNNN.
在任何 Python 版本上,將此設定為 false 都是安全的。它在不支援的舊版本或新版本上不會產生任何影響。不要假設該屬性可讀。儘管有此名稱,但 true 值並不表示將使用相應的函式,而只是表示可能使用。
當您不得不使用這些私有選項時,請提交問題,並提供重現您所遇到的問題的方法。在您的程式碼註釋中連結到該問題。
3.8 版本新增: _USE_POSIX_SPAWN