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()
,進而傳遞給子程序的標準輸入 (stdin)。如果使用該引數,則必須是位元組序列,或者如果指定了 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
。此對映可以是任何平臺上的 str 到 str,或者像os.environ
或os.environb
一樣,是 POSIX 平臺上的 bytes 到 bytes。示例
>>> 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 版本中變更: 更改了
shell=True
的 Windows shell 搜尋順序。當前目錄和%PATH%
被替換為%COMSPEC%
和%SystemRoot%\System32\cmd.exe
。因此,將名為cmd.exe
的惡意程式放入當前目錄不再有效。
- class subprocess.CompletedProcess¶
run()
的返回值,表示已完成的程序。- args¶
用於啟動程序的引數。 這可以是一個列表或一個字串。
- returncode¶
子程序的退出狀態。 通常,退出狀態為 0 表示它已成功執行。
負值
-N
表示子程序因訊號N
而終止(僅限 POSIX)。
- stdout¶
從子程序捕獲的 stdout。 位元組序列,或者如果呼叫
run()
時使用了 encoding、errors 或 text=True,則為字串。 如果未捕獲 stdout,則為None
。如果使用
stderr=subprocess.STDOUT
執行該程序,則 stdout 和 stderr 將在此屬性中合併,並且stderr
將為None
。
- stderr¶
從子程序捕獲的 stderr。 位元組序列,或者如果呼叫
run()
時使用了 encoding、errors 或 text=True,則為字串。 如果未捕獲 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
。 當捕獲到任何輸出時,這始終是bytes
,無論text=True
設定如何。當沒有觀察到輸出時,它可能會保持為None
而不是b''
。
- stderr¶
如果子程序被
run()
捕獲,則為子程序的 stderr 輸出。 否則,為None
。 當捕獲到 stderr 輸出時,這始終是bytes
,無論text=True
設定如何。當沒有觀察到 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'
。有關詳細資訊,請參閱當建構函式的 *newline* 引數為None
時,io.TextIOWrapper
類的文件。如果未使用文字模式,則 *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 管道、檔名萬用字元、環境變數擴充套件以及將~
擴充套件為使用者的 home 目錄),這可能很有用。但是,請注意,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 系統上,該類使用 Windows 的CreateProcess()
函式。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
,則 args 引數接受路徑類物件,在 POSIX 系統上接受包含路徑類物件的序列。在 3.8 版本中更改: 如果 shell 為
False
,則 args 引數接受路徑類物件,在 Windows 系統上接受包含位元組和路徑類物件的序列。shell 引數(預設為
False
)指定是否將 shell 用作要執行的程式。如果 shell 為True
,建議將 args 作為字串而不是序列傳遞。在
shell=True
的 POSIX 系統上,shell 預設為/bin/sh
。如果 args 是一個字串,則該字串指定透過 shell 執行的命令。這意味著該字串的格式必須與在 shell 提示符下鍵入的格式完全相同。這包括,例如,對包含空格的檔名進行引用或反斜槓轉義。如果 args 是一個序列,則第一項指定命令字串,任何其他項都將被視為 shell 本身的附加引數。也就是說,Popen
的作用等同於Popen(['/bin/sh', '-c', args[0], args[1], ...])
在
shell=True
的 Windows 系統上,COMSPEC
環境變數指定預設 shell。在 Windows 上,唯一需要指定shell=True
的情況是,當要執行的命令內置於 shell 中時(例如 dir 或 copy)。您不需要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 版本中變更: 更改了
shell=True
的 Windows shell 搜尋順序。當前目錄和%PATH%
被替換為%COMSPEC%
和%SystemRoot%\System32\cmd.exe
。因此,將名為cmd.exe
的惡意程式放入當前目錄不再有效。stdin、stdout 和 stderr 分別指定已執行程式的標準輸入、標準輸出和標準錯誤檔案控制代碼。有效值是
None
,PIPE
,DEVNULL
,現有檔案描述符(正整數)和一個具有有效檔案描述符的現有 檔案物件。使用None
的預設設定,不會發生重定向。PIPE
表示應該為子程序建立一個新的管道。DEVNULL
表示將使用特殊檔案os.devnull
。此外,stderr 可以是STDOUT
,這表示應用程式的標準錯誤資料應捕獲到與 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 的所有訊號將在 exec 之前在子程序中恢復為 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()
以獲得更好的效能。在 Windows Linux 子系統和 QEMU 使用者模擬中,使用os.posix_spawn()
的 Popen 建構函式不再在出現類似程式缺失的錯誤時引發異常,而是子程序會以非零的returncode
失敗。
異常¶
在子程序中,在新的程式開始執行之前引發的異常,將在父程序中重新引發。
最常見的引發的異常是 OSError
。例如,當嘗試執行不存在的檔案時會發生這種情況。應用程式應為 OSError
異常做好準備。請注意,當 shell=True
時,僅當找不到選定的 shell 本身時,子程序才會引發 OSError
。要確定 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
,則這是生成的外殼的程序 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()
臨時設定為可繼承的,否則會引發帶有 Windows 錯誤ERROR_INVALID_PARAMETER
(87) 的OSError
。警告
在多執行緒程序中,當將此功能與併發呼叫其他繼承所有控制代碼的程序建立函式(例如
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.ABOVE_NORMAL_PRIORITY_CLASS¶
一個
Popen
creationflags
引數,用於指定新程序將具有高於平均值的優先順序。在 3.7 版本中新增。
- subprocess.BELOW_NORMAL_PRIORITY_CLASS¶
一個
Popen
creationflags
引數,用於指定新程序將具有低於平均值的優先順序。在 3.7 版本中新增。
- 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 版本中變更: 更改了
shell=True
的 Windows shell 搜尋順序。當前目錄和%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 版本中變更: 更改了
shell=True
的 Windows shell 搜尋順序。當前目錄和%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 版本中變更: 更改了
shell=True
的 Windows shell 搜尋順序。當前目錄和%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"])
Vector 示例
os.spawnvp(os.P_NOWAIT, path, args)
==>
Popen([path] + args[1:])
Environment 示例
os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env)
==>
Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"})
替換 os.popen()
, os.popen2()
, os.popen3()
¶
(child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize)
==>
p = Popen(cmd, shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdin, child_stdout) = (p.stdin, p.stdout)
(child_stdin,
child_stdout,
child_stderr) = os.popen3(cmd, mode, bufsize)
==>
p = Popen(cmd, shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
(child_stdin,
child_stdout,
child_stderr) = (p.stdin, p.stdout, p.stderr)
(child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize)
==>
p = Popen(cmd, shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)
返回碼處理的轉換如下:
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")
替換 popen2
模組中的函式¶
注意
如果 popen2 函式的 cmd 引數是一個字串,則該命令透過 /bin/sh 執行。如果它是一個列表,則該命令直接執行。
(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode)
==>
p = Popen("somestring", shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdout, child_stdin) = (p.stdout, p.stdin)
(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode)
==>
p = Popen(["mycmd", "myarg"], bufsize=bufsize,
stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdout, child_stdin) = (p.stdout, p.stdin)
popen2.Popen3
和 popen2.Popen4
的基本工作方式與 subprocess.Popen
相同,只是
舊版 Shell 呼叫函式¶
此模組還提供了來自 2.x commands
模組的以下舊版函式。這些操作隱式呼叫系統 shell,並且以上關於安全性和異常處理一致性的描述對這些函式無效。
- subprocess.getstatusoutput(cmd, *, encoding=None, errors=None)¶
返回在 shell 中執行 cmd 的
(exitcode, output)
。使用
Popen.check_output()
在 shell 中執行字串 cmd 並返回一個 2 元組(exitcode, output)
。encoding 和 errors 用於解碼輸出;有關更多詳細資訊,請參閱關於 常用引數 的說明。輸出中的尾部換行符會被刪除。命令的退出程式碼可以解釋為子程序的返回程式碼。示例
>>> 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 引數。
說明¶
在 Windows 上將引數序列轉換為字串¶
在 Windows 上,args 序列會被轉換為可以使用以下規則解析的字串(這與 MS C 執行時使用的規則相對應)
引數由空格分隔,空格可以是空格或製表符。
用雙引號括起來的字串被解釋為單個引數,而不管其中包含的空格如何。帶引號的字串可以嵌入到引數中。
前面有反斜槓的雙引號被解釋為字面雙引號。
反斜槓按字面解釋,除非它們緊鄰雙引號之前。
如果反斜槓緊鄰雙引號之前,則每對反斜槓被解釋為字面反斜槓。如果反斜槓的數量是奇數,則最後一個反斜槓將轉義下一個雙引號,如規則 3 中所述。
參見
shlex
提供解析和轉義命令列的模組。
停用 vfork()
或 posix_spawn()
的使用¶
在 Linux 上,subprocess
預設情況下,在安全的情況下內部使用 vfork()
系統呼叫,而不是 fork()
。這大大提高了效能。
如果您遇到需要阻止 Python 使用 vfork()
的極其不尋常的情況,可以將 subprocess._USE_VFORK
屬性設定為 false 值。
subprocess._USE_VFORK = False # See CPython issue gh-NNNNNN.
設定此值不會影響 posix_spawn()
的使用,它可能在其 libc 實現中內部使用 vfork()
。如果需要阻止使用它,則有一個類似的 subprocess._USE_POSIX_SPAWN
屬性。
subprocess._USE_POSIX_SPAWN = False # See CPython issue gh-NNNNNN.
在任何 Python 版本上將它們設定為 false 都是安全的。當不支援時,它們對較舊的版本沒有影響。不要假設可以讀取這些屬性。儘管它們有名稱,但 true 值並不表示將使用相應的函式,而只是可能使用。
如果您必須使用這些私有旋鈕,請隨時提交問題,並提供重現您遇到的問題的方法。請在程式碼的註釋中連結到該問題。
在 3.8 版本中新增: _USE_POSIX_SPAWN
在 3.11 版本中新增: _USE_VFORK