subprocess
--- 子進程管理
源代碼: Lib/subprocess.py
寫在前面:
感覺也就這倆有用:
subprocess.run()
subprocess.Popen() w下只能運行exe程序
run: 開啟一個進程 Python 3.5中新增的函數。執行指定的命令,等待命令執行完成后返回一個包含執行結果的CompletedProcess類的實例。
call()方法能便捷的調用一個程序,並得到執行的返回碼。該方法是同步執行,需要等待命令執行完成,並且stdout不能指向PIPE,默認繼承父進程的輸出。 執行指定的命令,返回命令執行狀態,其功能類似於os.system(cmd)。
Popen:開一個管道 后台異步運行 。subprocess可以使用Popen構造,功能更強大,使用更靈活,可以做到異步調用,實時交互等。
subprocess
模塊允許你生成新的進程,連接它們的輸入、輸出、錯誤管道,並且獲取它們的返回碼。此模塊打算代替一些老舊的模塊與功能:
os.system os.spawn*
在下面的段落中,你可以找到關於 subprocess
模塊如何代替這些模塊和功能的相關信息。
參見
PEP 324 -- 提出 subprocess 模塊的 PEP
使用 subprocess
模塊
推薦的調用子進程的方式是在任何它支持的用例中使用 run()
函數。對於更進階的用例,也可以使用底層的 Popen
接口。
run()
函數是在 Python 3.5 被添加的;如果你需要與舊版本保持兼容,查看 較舊的高階 API 段落。
-
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) -
運行被 arg 描述的指令. 等待指令完成, 然后返回一個
CompletedProcess
實例.以上顯示的參數僅僅是最簡單的一些,下面 常用參數 描述(因此在縮寫簽名中使用僅關鍵字標示)。完整的函數頭和
Popen
的構造函數一樣,此函數接受的大多數參數都被傳遞給該接口。(timeout, input, check 和 capture_output 除外)。如果 capture_output 設為 true,stdout 和 stderr 將會被捕獲。在使用時,內置的
Popen
對象將自動用stdout=PIPE
和stderr=PIPE
創建。stdout 和 stderr 參數不應當與 capture_output 同時提供。如果你希望捕獲並將兩個流合並在一起,使用stdout=PIPE
和stderr=STDOUT
來代替 capture_output。timeout 參數將被傳遞給
Popen.communicate()
。如果發生超時,子進程將被殺死並等待。TimeoutExpired
異常將在子進程中斷后被拋出。input 參數將被傳遞給
Popen.communicate()
以及子進程的 stdin。 如果使用此參數,它必須是一個字節序列。 如果指定了 encoding 或 errors 或者將 text 設置為True
,那么也可以是一個字符串。 當使用此參數時,在創建內部Popen
對象時將自動帶上stdin=PIPE
,並且不能再手動指定 stdin 參數。如果 check 設為 True, 並且進程以非零狀態碼退出, 一個
CalledProcessError
異常將被拋出. 這個異常的屬性將設置為參數, 退出碼, 以及標准輸出和標准錯誤, 如果被捕獲到.如果 encoding 或者 error 被指定, 或者 text 被設為 True, 標准輸入, 標准輸出和標准錯誤的文件對象將通過指定的 encoding 和 errors 以文本模式打開, 否則以默認的
io.TextIOWrapper
打開. universal_newline 參數等同於 text 並且提供了向后兼容性. 默認情況下, 文件對象是以二進制模式打開的.如果 env 不是
None
, 它必須是一個字典, 為新的進程設置環境變量; 它用於替換繼承的當前進程的環境的默認行為. 它將直接被傳遞給Popen
.示例:
>>> 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 形參.
-
class
subprocess.
CompletedProcess
-
run()
的返回值, 代表一個進程已經結束.-
args
-
被用作啟動進程的參數. 可能是一個列表或字符串.
-
returncode
-
子進程的退出狀態碼. 通常來說, 一個為 0 的退出碼表示進程運行正常.
一個負值
-N
表示子進程被信號N
中斷 (僅 POSIX).
-
stdout
-
從子進程捕獲到的標准輸出. 一個字節序列, 或一個字符串, 如果
run()
是設置了 encoding, errors 或者text=True
來運行的. 如果未有捕獲, 則為None
.如果你通過
stderr=subprocess.STDOUT
運行進程,標准輸入和標准錯誤將被組合在這個屬性中,並且stderr
將為None
。
-
stderr
-
捕獲到的子進程的標准錯誤. 一個字節序列, 或者一個字符串, 如果
run()
是設置了參數 encoding, errors 或者text=True
運行的. 如果未有捕獲, 則為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()
.
-
subprocess.
STDOUT
-
可被
Popen
的 stdin , stdout 或者 stderr 參數使用的特殊值, 表示標准錯誤與標准輸出使用同一句柄。
-
exception
subprocess.
SubprocessError
-
此模塊的其他異常的基類。
3.3 新版功能.
-
exception
subprocess.
TimeoutExpired
-
SubprocessError
的子類,等待子進程的過程中發生超時時被拋出。-
cmd
-
用於創建子進程的指令。
-
timeout
-
超時秒數。
-
output
-
子進程的輸出, 如果被
run()
或check_output()
捕獲。否則為None
。
-
stdout
-
對 output 的別名,對應的有
stderr
。
-
stderr
-
子進程的標准錯誤輸出,如果被
run()
捕獲。 否則為None
。
3.3 新版功能.
在 3.5 版更改: 添加了 stdout 和 stderr 屬性。
-
-
exception
subprocess.
CalledProcessError
-
SubprocessError
的子類,當一個被check_call()
或check_output()
函數運行的子進程返回了非零退出碼時被拋出。-
returncode
-
子進程的退出狀態。如果程序由一個信號終止,這將會被設為一個負的信號碼。
-
cmd
-
用於創建子進程的指令。
-
output
-
子進程的輸出, 如果被
run()
或check_output()
捕獲。否則為None
。
-
stdout
-
對 output 的別名,對應的有
stderr
。
-
stderr
-
子進程的標准錯誤輸出,如果被
run()
捕獲。 否則為None
。
在 3.5 版更改: 添加了 stdout 和 stderr 屬性。
-
常用參數
為了支持豐富的使用案例, Popen
的構造函數(以及方便的函數)接受大量可選的參數。對於大多數典型的用例,許多參數可以被安全地留以它們的默認值。通常需要的參數有:
args 被所有調用需要,應當為一個字符串,或者一個程序參數序列。提供一個參數序列通常更好,它可以更小心地使用參數中的轉義字符以及引用(例如允許文件名中的空格)。如果傳遞一個簡單的字符串,則 shell 參數必須為
True
(見下文)或者該字符串中將被運行的程序名必須用簡單的命名而不指定任何參數。stdin, stdout 和 stderr 分別指定了執行的程序的標准輸入、輸出和標准錯誤文件句柄。合法的值有
PIPE
、DEVNULL
、 一個現存的文件描述符(一個正整數)、一個現存的文件對象以及None
。PIPE
表示應該新建一個對子進程的管道。DEVNULL
表示使用特殊的文件os.devnull
。當使用默認設置None
時,將不會進行重定向,子進程的文件流將繼承自父進程。另外, stderr 可能為STDOUT
,表示來自於子進程的標准錯誤數據應該被 stdout 相同的句柄捕獲。如果 encoding 或 errors 被指定,或者 text (也名為 universal_newlines)為真,則文件對象 stdin 、 stdout 與 stderr 將會使用在此次調用中指定的 encoding 和 errors 以文本模式打開或者為默認的
io.TextIOWrapper
。當構造函數的 newline 參數為
None
時。對於 stdin, 輸入的換行符'\n'
將被轉換為默認的換行符os.linesep
。對於 stdout 和 stderr, 所有輸出的換行符都被轉換為'\n'
。更多信息,查看io.TextIOWrapper
類的文檔。如果文本模式未被使用, stdin, stdout 和 stderr 將會以二進制流模式打開。沒有編碼與換行符轉換發生。
3.6 新版功能: 添加了 encoding 和 errors 形參。
3.7 新版功能: 添加了 text 形參作為 universal_newlines 的別名。
注解
文件對象
Popen.stdin
、Popen.stdout
和Popen.stderr
的換行符屬性不會被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_newline 被設為
True
,則類使用locale.getpreferredencoding(False)
編碼來代替locale.getpreferredencoding()
。關於它們的區別的更多信息,見io.TextIOWrapper
。注解
在使用
shell=True
之前, 請閱讀 Security Considerations 段落。
這些選項以及所有其他選項在 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) -
在一個新的進程中執行子程序。 在 POSIX 上,該類會使用類似於
os.execvpe()
的行為來執行子程序。 在 Windows 上,該類會使用 WindowsCreateProcess()
函數。Popen
的參數如下。args 應當是一個程序參數的序列或者是一個單獨的字符串或 path-like object。 默認情況下,如果 args 是序列則要運行的程序為 args 中的第一項。 如果 args 是字符串,則其解讀依賴於具體平台,如下所述。 請查看 shell 和 executable 參數了解其與默認行為的其他差異。 除非另有說明,否則推薦以序列形式傳入 args。
警告
為了最大化可靠性,請使用可執行文件的完整限定路徑。 要在
PATH
中搜索一個未限定名稱,請使用shutil.which()
。 在所有平台上,傳入sys.executable
是再次啟動當前 Python 解釋器的推薦方式,並請使用-m
命令行格式來啟動已安裝的模塊。對 executable (或 args 的第一項) 路徑的解析方式依賴於具體平台。 對於 POSIX,請參閱
os.execvpe()
,並要注意當解析或搜索可執行文件路徑時,cwd 會覆蓋當前工作目錄而 env 可以覆蓋PATH
環境變量。 對於 Windows,請參閱lpApplicationName
的文檔以及lpCommandLine
形參 (傳給 WinAPICreateProcess
),並要注意當解析或搜索可執行文件路徑時如果傳入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 版更改: 在 POSIX 上如果 shell 為
False
並且序列包含路徑類對象則 args 形參可以接受一個 path-like object。在 3.8 版更改: 如果在Windows 上 shell 為
False
並且序列包含字節串和路徑類對象則 args 形參可以接受一個 path-like object。參數 shell (默認為
False
)指定是否使用 shell 執行程序。如果 shell 為True
,更推薦將 args 作為字符串傳遞而非序列。在 POSIX,當
shell=True
, shell 默認為/bin/sh
。如果 args 是一個字符串,此字符串指定將通過 shell 執行的命令。這意味着字符串的格式必須和在命令提示符中所輸入的完全相同。這包括,例如,引號和反斜杠轉義包含空格的文件名。如果 args 是一個序列,第一項指定了命令,另外的項目將作為傳遞給 shell (而非命令) 的參數對待。也就是說,Popen
等同於:Popen(['/bin/sh', '-c', args[0], args[1], ...])
在 Windows,使用
shell=True
,環境變量COMSPEC
指定了默認 shell。在 Windows 你唯一需要指定shell=True
的情況是你想要執行內置在 shell 中的命令(例如 dir 或者 copy)。在運行一個批處理文件或者基於控制台的可執行文件時,不需要shell=True
。注解
在使用
shell=True
之前, 請閱讀 Security Considerations 段落。bufsize 將在
open()
函數創建了 stdin/stdout/stderr 管道文件對象時作為對應的參數供應:-
0
表示不使用緩沖區 (讀取與寫入是一個系統調用並且可以返回短內容) -
1
表示行緩沖(只有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=True
, executable 替換 args 指定運行的程序。但是,原始的 args 仍然被傳遞給程序。大多數程序將被 args 指定的程序作為命令名對待,這可以與實際運行的程序不同。在 POSIX, args 名作為實際調用程序中可執行文件的顯示名稱,例如 ps。如果shell=True
,在 POSIX, executable 參數指定用於替換默認 shell/bin/sh
的 shell。在 3.6 版更改: 在POSIX 上 executable 形參可以接受一個 path-like object。
在 3.8 版更改: 在Windows 上 executable 形參可以接受一個字節串和 path-like object。
stdin, stdout 和 stderr 分別指定被運行的程序的標准輸入、輸出和標准錯誤的文件句柄。合法的值有
PIPE
,DEVNULL
, 一個存在的文件描述符(一個正整數),一個存在的 文件對象 以及None
。PIPE
表示應創建一個新的對子進程的管道。DEVNULL
表示使用特殊的os.devnull
文件。使用默認的None
,則不進行成定向;子進程的文件流將繼承自父進程。另外, stderr 可設為STDOUT
,表示應用程序的標准錯誤數據應和標准輸出一同捕獲。如果 preexec_fn 被設為一個可調用對象,此對象將在子進程剛創建時被調用。(僅 POSIX)
警告
preexec_fn 形參在應用程序中存在多線程時是不安全的。子進程在調用前可能死鎖。如果你必須使用它,保持警惕!最小化你調用的庫的數量。
注解
如果你需要修改子進程環境,使用 env 形參而非在 preexec_fn 中進行。 start_new_session 形參可以代替之前常用的 preexec_fn 來在子進程中調用 os.setsid()。
在 3.8 版更改: preexec_fn 形參在子解釋器中已不再受支持。 在子解釋器中使用此形參將引發
RuntimeError
。 這個新限制可能會影響部署在 mod_wsgi, uWSGI 和其他嵌入式環境中的應用。如果 close_fds 為真,所有文件描述符除了
0
,1
,2
之外都會在子進程執行前關閉。而當 close_fds 為假時,文件描述符遵守它們繼承的標志,如 文件描述符的繼承 所述。在 Windows,如果 close_fds 為真, 則子進程不會繼承任何句柄,除非在
STARTUPINFO.IpAttributeList
的handle_list
的鍵中顯式傳遞,或者通過標准句柄重定向傳遞。在 3.2 版更改: close_fds 的默認值已經從
False
修改為上述值。在 3.7 版更改: 在 Windows,當重定向標准句柄時 close_fds 的默認值從
False
變為True
。現在重定向標准句柄時有可能設置 close_fds 為True
。(標准句柄指三個 stdio 的句柄)pass_fds 是一個可選的在父子進程間保持打開的文件描述符序列。提供任何 pass_fds 將強制 close_fds 為
True
。(僅 POSIX)在 3.2 版更改: 加入了 pass_fds 形參。
如果 cwd 不為
None
,此函數在執行子進程前會將當前工作目錄改為 cwd。 cwd 可以是一個字符串、字節串或 路徑類對象。 在 POSIX 上,如果可執行文件路徑為相對路徑則此函數會相對於 cwd 來查找 executable (或 args 的第一項)。在 3.6 版更改: 在 POSIX 上 cwd 形參接受一個 path-like object。
在 3.7 版更改: 在 Windows 上 cwd 形參接受一個 path-like object。
在 3.8 版更改: 在 Windows 上 cwd 形參接受一個字節串對象。
如果 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 被添加。
如果 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
,則必須為一個為新進程定義了環境變量的字典;這些用於替換繼承的當前進程環境的默認行為。注解
如果指定, env 必須提供所有被子進程需求的變量。在 Windows,為了運行一個 side-by-side assembly ,指定的 env 必須 包含一個有效的
SystemRoot
。如果 encoding 或 errors 被指定,或者 text 為 true,則文件對象 stdin, stdout 和 stderr 將會以指定的編碼和 errors 以文本模式打開,如同 常用參數 所述。 universal_newlines 參數等同於 text 並且提供向后兼容性。默認情況下,文件對象都以二進制模式打開。
3.6 新版功能: encoding 和 errors 被添加。
3.7 新版功能: text 作為 universal_newlines 的一個更具可讀性的別名被添加。
如果給出, startupinfo 將是一個將被傳遞給底層的
CreateProcess
函數的STARTUPINFO
對象。 creationflags,如果給出,可以是一個或多個以下標志之一:當
PIPE
被用作 stdin, stdout 或 stderr 時 pipesize 可被用於改變管道的大小。 管道的大小僅會在受支持的平台上被改變(當撰寫本文檔時只有 Linux 支持)。 其他平台將忽略此形參。3.10 新版功能: 增加了
pipesize
形參。Popen 對象支持通過
with
語句作為上下文管理器,在退出時關閉文件描述符並等待進程:with Popen(["ifconfig"], stdout=PIPE) as proc: log.write(proc.stdout.read())
引發一個 審計事件
subprocess.Popen
,附帶參數executable
,args
,cwd
,env
。在 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 形參的函數與方法,例如 call()
和 Popen.communicate()
將會在進程退出前超時到期時拋出 TimeoutExpired
。
此模塊中定義的異常都繼承自 SubprocessError
。
3.3 新版功能: 基類
SubprocessError
被添加。
安全考量
不同於某些其他的 popen 函數,這個實現絕不會隱式地調用系統 shell。 這意味着所有字符,包括 shell 元字符,都可以安全地被傳遞給子進程。 如果 shell 通過 shell=True
被顯式地發起調用,則應用程序有責任確保所有空白符和元字符被適當地轉義以避免 shell 注入 漏洞。 在 某些平台 上,可以使用 shlex.quote()
來執行這樣的轉義。
Popen 對象
Popen
類的實例擁有以下方法:
-
Popen.
poll
() -
檢查子進程是否已被終止。設置並返回
returncode
屬性。否則返回None
。
-
Popen.
wait
(timeout=None) -
等待子進程被終止。設置並返回
returncode
屬性。如果進程在 timeout 秒后未中斷,拋出一個
TimeoutExpired
異常,可以安全地捕獲此異常並重新等待。注解
當
stdout=PIPE
或者stderr=PIPE
並且子進程產生了足以阻塞 OS 管道緩沖區接收更多數據的輸出到管道時,將會發生死鎖。當使用管道時用Popen.communicate()
來規避它。注解
此函數使用了一個 busy loop (非阻塞調用以及短睡眠) 實現。使用
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
的 creationflags 形參啟動的進程。
-
Popen.
terminate
() -
停止子進程。 在 POSIX 操作系統上,此方法會發送 SIGTERM 給子進程。 在 Windows 上則會調用 Win32 API 函數
TerminateProcess()
來停止子進程。
-
Popen.
kill
() -
殺死子進程。 在 POSIX 操作系統上,此函數會發送 SIGKILL 給子進程。 在 Windows 上
kill()
則是terminate()
的別名。
以下屬性也是可用的:
-
Popen.
args
-
args 參數傳遞給
Popen
-- 一個程序參數的序列或者一個簡單字符串。3.3 新版功能.
-
Popen.
stdin
-
如果 stdin 參數為
PIPE
,此屬性是一個類似open()
返回的可寫的流對象。如果 encoding 或 errors 參數被指定或者 universal_newlines 參數為True
,則此流是一個文本流,否則是字節流。如果 stdin 參數非PIPE
, 此屬性為None
。
-
Popen.
stdout
-
如果 stdout 參數是
PIPE
,此屬性是一個類似open()
返回的可讀流。從流中讀取子進程提供的輸出。如果 encoding 或 errors 參數被指定或者 universal_newlines 參數為True
,此流為文本流,否則為字節流。如果 stdout 參數非PIPE
,此屬性為None
。
-
Popen.
stderr
-
如果 stderr 參數是
PIPE
,此屬性是一個類似open()
返回的可讀流。從流中讀取子進程提供的輸出。如果 encoding 或 errors 參數被指定或者 universal_newlines 參數為True
,此流為文本流,否則為字節流。如果 stderr 參數非PIPE
,此屬性為None
。
警告
使用 communicate()
而非 .stdin.write
, .stdout.read
或者 .stderr.read
來避免由於任意其他 OS 管道緩沖區被子進程填滿阻塞而導致的死鎖。
-
Popen.
pid
-
子進程的進程號。
注意如果你設置了 shell 參數為
True
,則這是生成的子 shell 的進程號。
-
Popen.
returncode
-
此進程的退出碼,由
poll()
和wait()
設置(以及直接由communicate()
設置)。一個None
值 表示此進程仍未結束。一個負值
-N
表示子進程被信號N
中斷 (僅 POSIX).
Windows Popen 助手
STARTUPINFO
類和以下常數僅在 Windows 有效。
-
class
subprocess.
STARTUPINFO
(*, dwFlags=0, hStdInput=None, hStdOutput=None, hStdError=None, wShowWindow=0, lpAttributeList=None) -
在
Popen
創建時部分支持 Windows 的 STARTUPINFO 結構。接下來的屬性僅能通過關鍵詞參數設置。在 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 errorERROR_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.
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=PIPE
或stderr=PIPE
。 如果子進程向管道生成了足以填滿 OS 管理緩沖區的輸出而管道還未被讀取時它將會阻塞。在 3.3 版更改: timeout 被添加
-
subprocess.
check_call
(args, *, stdin=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None, **other_popen_kwargs) -
附帶參數運行命令。 等待命令完成。 如果返回碼為零則正常返回,否則引發
CalledProcessError
。CalledProcessError
對象將在returncode
屬性中保存返回碼。需要捕獲 stdout 或 stderr 的代碼應當改用
run()
:run(..., check=True)
要屏蔽 stdout 或 stderr,可提供
DEVNULL
這個值。上面顯示的參數只是常見的一些。 完整的函數簽名與
Popen
構造器的相同 —— 此函數會將所提供的 timeout 之外的全部參數直接傳遞給目標接口。注解
請不要在此函數中使用
stdout=PIPE
或stderr=PIPE
。 如果子進程向管道生成了足以填滿 OS 管理緩沖區的輸出而管道還未被讀取時它將會阻塞。在 3.3 版更改: timeout 被添加
-
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 的一個更具可讀性的別名被添加。
使用 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()
調用很重要,這是為了讓 p1 能在 p2 先於 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) -
返回在 shell 中執行 cmd 產生的
(exitcode, output)
。在 shell 中以
Popen.check_output()
執行字符串 cmd 並返回一個 2 元組(exitcode, output)
。 會使用當前區域設置的編碼格式;請參閱 常用參數 中的說明來了解詳情。末尾的一個換行符會從輸出中被去除。 命令的退出碼可被解讀為子進程的返回碼。 例如:
>>> 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, '')
可用性: POSIX 和 Windows。
在 3.3.4 版更改: 添加了 Windows 支持。
此函數現在返回 (exitcode, output) 而不是像 Python 3.3.3 及更早的版本那樣返回 (status, output)。 exitcode 的值與
returncode
相同。
-
subprocess.
getoutput
(cmd) -
返回在 shell 中執行 cmd 產生的輸出(stdout 和 stderr)。
類似於
getstatusoutput()
,但退出碼會被忽略並且返回值為包含命令輸出的字符串。 例如:>>> subprocess.getoutput('ls /bin/ls') '/bin/ls'
可用性: POSIX 和 Windows。
在 3.3.4 版更改: 添加了 Windows 支持
備注
在 Windows 上將參數列表轉換為一個字符串
在 Windows 上,args 序列會被轉換為可使用以下規則來解析的字符串(對應於 MS C 運行時所使用的規則):
-
參數以空白符分隔,即空格符或制表符。
-
用雙引號標示的字符串會被解讀為單個參數,而不再考慮其中的空白符。 一個參數可以嵌套用引號標示的字符串。
-
帶有一個反斜杠前綴的雙引號會被解讀為雙引號字面值。
-
反斜杠會按字面值解讀,除非它是作為雙引號的前綴。
-
如果反斜杠被作為雙引號的前綴,則每個反斜杠對會被解讀為一個反斜杠字面值。 如果反斜杠數量為奇數,則最后一個反斜杠會如規則 3 所描述的那樣轉義下一個雙引號。