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 建構函式的簽名大致相同——此函式的大多數引數都傳遞給該介面。(timeoutinputcheckcapture_output 除外。)

如果 capture_output 為 true,則 stdout 和 stderr 將被捕獲。使用時,內部 Popen 物件會自動建立,其 stdoutstderr 都設定為 PIPE。不能同時提供 stdoutstderr 引數以及 capture_output。如果您希望捕獲並將兩個流合併為一個,請將 stdout 設定為 PIPE,將 stderr 設定為 STDOUT,而不是使用 capture_output

可以指定以秒為單位的 timeout,它在內部傳遞給 Popen.communicate()。如果超時,子程序將被殺死並等待。在子程序終止後,TimeoutExpired 異常將被重新引發。在許多平臺 API 上,初始程序建立本身無法中斷,因此您無法保證在程序建立所需時間之前看到超時異常。

input 引數傳遞給 Popen.communicate(),從而傳遞給子程序的標準輸入。如果使用,它必須是位元組序列,如果指定了 encodingerrorstext 為 true,則必須是字串。使用時,內部 Popen 物件會自動建立,其 stdin 設定為 PIPE,並且不能同時使用 stdin 引數。

如果 check 為 true,並且程序以非零退出程式碼退出,則將引發 CalledProcessError 異常。該異常的屬性包含引數、退出程式碼以及 stdout 和 stderr(如果它們被捕獲)。

如果指定了 encodingerrors,或者 text 為 true,則 stdin、stdout 和 stderr 的檔案物件將以文字模式開啟,使用指定的 encodingerrorsio.TextIOWrapper 預設值。universal_newlines 引數等同於 text,是為了向後相容而提供的。預設情況下,檔案物件以二進位制模式開啟。

如果 env 不為 None,它必須是一個定義新程序環境變數的對映;這些變數用於代替繼承當前程序環境的預設行為。它直接傳遞給 Popen。此對映可以是任意平臺上的字串到字串,或 POSIX 平臺上的位元組到位元組,類似於 os.environos.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 版中變更: 添加了 encodingerrors 引數

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

stderr

從子程序捕獲的 stderr。一個位元組序列,如果呼叫 run() 時帶有編碼、錯誤或 text=True,則為字串。如果未捕獲 stderr,則為 None

check_returncode()

如果 returncode 不為零,則引發 CalledProcessError

在 3.5 版本加入。

subprocess.DEVNULL

一個特殊值,可用作 Popenstdinstdoutstderr 引數,表示將使用特殊檔案 os.devnull

在 3.3 版本加入。

subprocess.PIPE

一個特殊值,可用作 Popenstdinstdoutstderr 引數,表示應開啟到標準流的管道。最常與 Popen.communicate() 一起使用。

subprocess.STDOUT

一個特殊值,可用作 Popenstderr 引數,表示標準錯誤應進入與標準輸出相同的控制代碼。

exception subprocess.SubprocessError

此模組中所有其他異常的基類。

在 3.3 版本加入。

exception subprocess.TimeoutExpired

SubprocessError 的子類,在等待子程序時超時時引發。

cmd

用於生成子程序的命令。

timeout

超時時間(秒)。

output

如果透過 run()check_output() 捕獲,則為子程序的輸出。否則為 None。無論 text=True 設定如何,只要捕獲到任何輸出,這始終是 bytes。如果沒有觀察到輸出,它可能保持 None 而不是 b''

stdout

output 的別名,與 stderr 對稱。

stderr

如果透過 run() 捕獲,則為子程序的 stderr 輸出。否則為 None。無論 text=True 設定如何,只要捕獲到 stderr 輸出,這始終是 bytes。如果沒有觀察到 stderr 輸出,它可能保持 None 而不是 b''

在 3.3 版本加入。

3.5 版中變更: 添加了 stdoutstderr 屬性

exception subprocess.CalledProcessError

SubprocessError 的子類,當由 check_call()check_output()run() (帶 check=True) 執行的程序返回非零退出狀態時引發。

returncode

子程序的退出狀態。如果程序因訊號退出,這將是負訊號數。

cmd

用於生成子程序的命令。

output

如果透過 run()check_output() 捕獲,則為子程序的輸出。否則為 None

stdout

output 的別名,與 stderr 對稱。

stderr

如果透過 run() 捕獲,則為子程序的 stderr 輸出。否則為 None

3.5 版中變更: 添加了 stdoutstderr 屬性

常用引數

為了支援各種用例,Popen 建構函式(和便利函式)接受大量可選引數。對於大多數典型用例,許多這些引數可以安全地保留其預設值。最常用的引數是

args 是所有呼叫都必需的,它應該是一個字串或程式引數序列。通常建議提供一個引數序列,因為它允許模組處理任何所需的轉義和引數引用(例如,允許檔名中包含空格)。如果傳遞單個字串,則 shell 必須為 True (見下文),否則該字串必須只是要執行的程式的名稱,而不指定任何引數。

stdin, stdoutstderr 分別指定了被執行程式的標準輸入、標準輸出和標準錯誤檔案控制代碼。有效值為 None, PIPE, DEVNULL, 一個現有檔案描述符(正整數), 以及一個具有有效檔案描述符的現有檔案物件。在預設設定為 None 的情況下,不會發生重定向。PIPE 表示應該建立一個到子程序的新管道。DEVNULL 表示將使用特殊檔案 os.devnull。此外,stderr 可以是 STDOUT,這表示子程序的 stderr 資料應該捕獲到與 stdout 相同的 檔案控制代碼中。

如果指定了 encodingerrors,或者 text (也稱為 universal_newlines) 為真,則檔案物件 stdin, stdoutstderr 將以文字模式開啟,使用呼叫中指定的 encodingerrors,或者 io.TextIOWrapper 的預設值。

對於 stdin,輸入中的換行符 '\n' 將轉換為預設的行分隔符 os.linesep。對於 stdoutstderr,輸出中的所有換行符都將轉換為 '\n'。更多資訊請參閱 io.TextIOWrapper 類的文件,當其建構函式的 newline 引數為 None 時。

如果未使用文字模式,stdinstdoutstderr 將作為二進位制流開啟。不執行編碼或行尾轉換。

3.6 版中變更: 添加了 encodingerrors 引數。

3.7 版中變更: 添加了 text 引數作為 universal_newlines 的別名。

備註

檔案物件 Popen.stdinPopen.stdoutPopen.stderr 的 newlines 屬性不會被 Popen.communicate() 方法更新。

如果 shellTrue,則指定的命令將透過 shell 執行。這在您主要使用 Python 來增強對大多數系統 shell 的控制流,但仍希望方便地訪問其他 shell 功能(如 shell 管道、檔名萬用字元、環境變數擴充套件以及將 ~ 擴充套件到使用者主目錄)時非常有用。但是,請注意 Python 本身提供了許多類似 shell 的功能實現(特別是 globfnmatchos.walk()os.path.expandvars()os.path.expanduser()shutil)。

3.3 版中變更: universal_newlinesTrue 時,該類使用編碼 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 是一個字串,則解釋是平臺相關的,如下所述。有關與預設行為的其他差異,請參閱 shellexecutable 引數。除非另有說明,建議將 args 作為序列傳遞。

警告

為了獲得最大的可靠性,請為可執行檔案使用完全限定路徑。要在 PATH 上搜索不合格的名稱,請使用 shutil.which()。在所有平臺上,傳遞 sys.executable 是再次啟動當前 Python 直譯器並使用 -m 命令列格式啟動已安裝模組的推薦方式。

解析 executable(或 args 的第一個專案)的路徑是平臺相關的。對於 POSIX,請參閱 os.execvpe(),並注意在解析或搜尋可執行檔案路徑時,cwd 會覆蓋當前工作目錄,env 可以覆蓋 PATH 環境變數。對於 Windows,請參閱 WinAPI CreateProcesslpApplicationNamelpCommandLine 引數的文件,並注意在使用 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 版中變更: 如果 shellFalse 且 POSIX 上包含類路徑物件的序列,則 args 引數接受 類路徑物件

3.8 版中變更: 如果 shellFalse 且 Windows 上包含位元組和類路徑物件的序列,則 args 引數接受 類路徑物件

shell 引數(預設為 False)指定是否將 shell 用作要執行的程式。如果 shellTrue,建議將 args 作為字串而不是序列傳遞。

在 POSIX 上,如果 shell=True,shell 預設為 /bin/sh。如果 args 是一個字串,該字串指定透過 shell 執行的命令。這意味著該字串必須與在 shell 提示符下鍵入時完全相同的格式。例如,這包括對包含空格的檔名進行引號或反斜槓轉義。如果 args 是一個序列,第一個專案指定命令字串,任何額外的專案將被視為 shell 本身的額外引數。也就是說,Popen 執行等同於

Popen(['/bin/sh', '-c', args[0], args[1], ...])

在 Windows 上,如果 shell=TrueCOMSPEC 環境變數指定預設 shell。您只需要在要執行的命令是 shell 的內建命令(例如 dircopy)時才需要在 Windows 上指定 shell=True。您不需要 shell=True 來執行批處理檔案或基於控制檯的可執行檔案。

備註

在使用 shell=True 之前,請閱讀 安全注意事項 部分。

在建立 stdin/stdout/stderr 管道檔案物件時,bufsize 將作為相應的引數提供給 open() 函式

  • 0 表示無緩衝(讀寫是一個系統呼叫,可能返回短資料)

  • 1 表示行緩衝(僅在 text=Trueuniversal_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 的惡意程式不再有效。

stdinstdoutstderr 分別指定了被執行程式的標準輸入、標準輸出和標準錯誤檔案控制代碼。有效值為 NonePIPEDEVNULL、一個現有檔案描述符(正整數)以及一個具有有效檔案描述符的現有檔案物件。在預設設定為 None 的情況下,不會發生重定向。PIPE 表示應該建立一個到子程序的新管道。DEVNULL 表示將使用特殊檔案 os.devnull。此外,stderr 可以是 STDOUT,這表示應用程式的 stderr 資料應該捕獲到與 stdout 相同的 檔案控制代碼中。

如果 preexec_fn 設定為一個可呼叫物件,則該物件將在子程序執行之前在子程序中呼叫。(僅限 POSIX)

警告

在應用程式中存線上程的情況下,preexec_fn 引數使用不安全。在呼叫 exec 之前,子程序可能會死鎖。

備註

如果您需要修改子程序的環境,請使用 env 引數,而不是在 preexec_fn 中進行。start_new_sessionprocess_group 引數應該取代使用 preexec_fn 在子程序中呼叫 os.setsid()os.setpgid() 的程式碼。

3.8 版中變更: 子直譯器不再支援 preexec_fn 引數。在子直譯器中使用該引數會引發 RuntimeError。新的限制可能會影響部署在 mod_wsgi、uWSGI 和其他嵌入式環境中的應用程式。

如果 close_fds 為 true,則除 012 之外的所有檔案描述符都將在子程序執行之前關閉。否則,當 close_fds 為 false 時,檔案描述符將遵循 檔案描述符的繼承 中所述的其可繼承標誌。

在 Windows 上,如果 close_fds 為 true,則子程序不會繼承任何控制代碼,除非在 STARTUPINFO.lpAttributeListhandle_list 元素中明確傳遞,或透過標準控制代碼重定向。

3.2 版中變更: close_fds 的預設值已從 False 更改為上面描述的值。

3.7 版中變更: 在 Windows 上,當重定向標準控制代碼時,close_fds 的預設值從 False 更改為 True。現在,當重定向標準控制代碼時,可以將 close_fds 設定為 True

pass_fds 是一個可選的檔案描述符序列,用於在父程序和子程序之間保持開啟。提供任何 pass_fds 會強制 close_fdsTrue。(僅限 POSIX)

3.2 版中變更: 添加了 pass_fds 引數。

如果 cwd 不為 None,則函式在執行子程序之前將工作目錄更改為 cwdcwd 可以是字串、位元組或 類路徑 物件。在 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.environos.environb

備註

如果指定了 env,則 env 必須提供程式執行所需的所有變數。在 Windows 上,為了執行 並行程式集,指定的 env 必須 包含一個有效的 %SystemRoot%

如果指定了 encodingerrors,或者 text 為 true,則檔案物件 stdinstdoutstderr 將以文字模式開啟,並使用指定的 encodingerrors,如上文 常用引數 中所述。universal_newlines 引數等同於 text,是為了向後相容而提供的。預設情況下,檔案物件以二進位制模式開啟。

3.6 版新增: 添加了 encodingerrors

3.7 版新增: 添加了 text 作為 universal_newlines 的更具可讀性的別名。

如果提供了 startupinfo,它將是一個 STARTUPINFO 物件,該物件將傳遞給底層的 CreateProcess 函式。

如果給定 creationflags,它可以是以下一個或多個標誌

stdinstdoutstderr 使用 PIPE 時,可以使用 pipesize 來更改管道的大小。管道的大小隻會在支援此功能的平臺(目前僅限 Linux)上更改。其他平臺將忽略此引數。

3.10 版中變更: 添加了 pipesize 引數。

Popen 物件透過 with 語句支援上下文管理器:退出時,標準檔案描述符關閉,並等待程序。

with Popen(["ifconfig"], stdout=PIPE) as proc:
    log.write(proc.stdout.read())

Popen 以及此模組中其他使用它的函式會引發一個 審計事件 subprocess.Popen,其引數為 executableargscwdenvargs 的值可能是一個字串或一個字串列表,具體取決於平臺。

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=PIPEstderr=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_GROUPcreationflags 引數啟動的程序。

Popen.terminate()

終止子程序。在 POSIX 作業系統上,該方法向子程序傳送 SIGTERM。在 Windows 上,呼叫 Win32 API 函式 TerminateProcess() 來終止子程序。

Popen.kill()

殺死子程序。在 POSIX 作業系統上,該函式向子程序傳送 SIGKILL。在 Windows 上,kill()terminate() 的別名。

該類還會為您設定以下屬性以供訪問。不支援將它們重新分配給新值

Popen.args

傳遞給 Popenargs 引數——一個程式引數序列或一個字串。

在 3.3 版本加入。

Popen.stdin

如果 stdin 引數是 PIPE,則此屬性是一個可寫入的流物件,由 open() 返回。如果指定了 encodingerrors 引數,或者 textuniversal_newlines 引數為 True,則該流是文字流,否則是位元組流。如果 stdin 引數不是 PIPE,則此屬性為 None

Popen.stdout

如果 stdout 引數是 PIPE,則此屬性是一個可讀的流物件,由 open() 返回。從該流讀取將提供子程序的輸出。如果指定了 encodingerrors 引數,或者 textuniversal_newlines 引數為 True,則該流是文字流,否則是位元組流。如果 stdout 引數不是 PIPE,則此屬性為 None

Popen.stderr

如果 stderr 引數是 PIPE,則此屬性是一個可讀的流物件,由 open() 返回。從該流讀取將提供子程序的錯誤輸出。如果指定了 encodingerrors 引數,或者 textuniversal_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 除外。否則,此屬性將被忽略。

SW_HIDE 為此屬性提供。當呼叫 Popenshell=True 時使用它。

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.hStdInputSTARTUPINFO.hStdOutputSTARTUPINFO.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.HIGH_PRIORITY_CLASS

一個 Popen creationflags 引數,用於指定新程序將具有高優先順序。

在 3.7 版本加入。

subprocess.IDLE_PRIORITY_CLASS

一個 Popen creationflags 引數,用於指定新程序將具有空閒(最低)優先順序。

在 3.7 版本加入。

subprocess.NORMAL_PRIORITY_CLASS

一個 Popen creationflags 引數,用於指定新程序將具有正常優先順序。(預設)

在 3.7 版本加入。

subprocess.REALTIME_PRIORITY_CLASS

一個 Popen creationflags 引數,用於指定新程序將具有即時優先順序。幾乎不應使用 REALTIME_PRIORITY_CLASS,因為它會中斷管理滑鼠輸入、鍵盤輸入和後臺磁碟重新整理的系統執行緒。此類別可能適用於直接與硬體“對話”或執行應受有限中斷的短暫任務的應用程式。

在 3.7 版本加入。

subprocess.CREATE_NO_WINDOW

一個 Popen creationflags 引數,用於指定新程序不會建立視窗。

在 3.7 版本加入。

subprocess.DETACHED_PROCESS

一個 Popen creationflags 引數,用於指定新程序不會繼承其父程序的控制檯。此值不能與 CREATE_NEW_CONSOLE 一起使用。

在 3.7 版本加入。

subprocess.CREATE_DEFAULT_ERROR_MODE

一個 Popen creationflags 引數,用於指定新程序不繼承呼叫程序的錯誤模式。相反,新程序獲取預設錯誤模式。此功能對於停用硬錯誤的多執行緒 shell 應用程式特別有用。

在 3.7 版本加入。

subprocess.CREATE_BREAKAWAY_FROM_JOB

一個 Popen creationflags 引數,用於指定新程序不與作業關聯。

在 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=PIPEstderr=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)

使用引數執行命令。等待命令完成。如果返回程式碼為零則返回,否則引發 CalledProcessErrorCalledProcessError 物件將在 returncode 屬性中包含返回程式碼。如果 check_call() 無法啟動程序,它將傳播引發的異常。

需要捕獲 stdout 或 stderr 的程式碼應改用 run()

run(..., check=True)

要抑制 stdout 或 stderr,請提供 DEVNULL 值。

上面顯示的引數只是一些常見的引數。完整的函式簽名與 Popen 建構函式的簽名相同 - 此函式將所有提供的引數(除了 timeout)直接傳遞給該介面。

備註

請勿在此函式中使用 stdout=PIPEstderr=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)

執行帶有引數的命令並返回其輸出。

如果返回程式碼非零,它將引發 CalledProcessErrorCalledProcessError 物件將在 returncode 屬性中包含返回程式碼,並在 output 屬性中包含任何輸出。

這等價於:

run(..., check=True, stdout=PIPE).stdout

上面顯示的引數只是一些常見的引數。完整的函式簽名與 run() 的大致相同——大多數引數直接傳遞給該介面。與 run() 行為的一個 API 差異是:傳遞 input=None 的行為與 input=b''(或 input='',取決於其他引數)相同,而不是使用父程序的標準輸入檔案控制代碼。

預設情況下,此函式將以編碼位元組的形式返回資料。輸出資料的實際編碼可能取決於所呼叫的命令,因此通常需要在應用程式級別處理文字解碼。

透過將 textencodingerrorsuniversal_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 版本中已更改: 增加了 encodingerrors。有關詳細資訊,請參見 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)encodingerrors 用於解碼輸出;有關詳細資訊,請參閱 常用引數 中的註釋。

輸出中的尾部換行符將被去除。命令的退出碼可以解釋為 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 版本中已更改: 增加了 encodingerrors 引數。

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 版本中已更改: 增加了 encodingerrors 引數。

註釋

超時行為

在使用 run()Popen.wait()Popen.communicate() 等函式中的 timeout 引數時,使用者應注意以下行為:

  1. 程序建立延遲:在許多平臺 API 上,初始程序建立本身無法中斷。這意味著即使指定了超時,也無法保證在程序建立所需時間之後才能看到超時異常。

  2. 極小的超時值:設定非常小的超時值(例如幾毫秒)可能會導致幾乎立即出現 TimeoutExpired 異常,因為程序建立和系統排程本身需要時間。

在 Windows 上將引數序列轉換為字串

在 Windows 上,args 序列被轉換為一個字串,可以使用以下規則進行解析(這些規則對應於 MS C 執行時使用的規則)

  1. 引數由空白符(空格或製表符)分隔。

  2. 用雙引號括起來的字串被解釋為單個引數,無論其中包含多少空白符。帶引號的字串可以嵌入到引數中。

  3. 前面帶反斜槓的雙引號被解釋為字面雙引號。

  4. 反斜槓被解釋為字面字元,除非它們緊跟在雙引號之前。

  5. 如果反斜槓緊跟在雙引號之前,每對反斜槓都被解釋為字面反斜槓。如果反斜槓的數量是奇數,則最後一個反斜槓會轉義下一個雙引號,如規則 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