python subprocess詳解
- python subprocess詳解
- 簡介:
- 運行python的時候,我們都是在創建並運行一個進程。像Linux進程那樣,一個進程可以fork一個子進程,並讓這個子進程exec另外一個程序。在Python中,我們通過標准庫中的subprocess包來fork一個子進程,並運行一個外部的程序。subprocess包中定義有數個創建子進程的函數,這些函數分別以不同的方式創建子進程,所以我們可以根據需要來從中選取一個使用。另外subprocess還提供了一些管理標准流(standard stream)和管道(pipe)的工具,從而在進程間使用文本通信。
- subprocess.call()
- subprocess.check_call()
- subprocess.check_output():
- subprocess.Popen():
簡介:
運行python的時候,我們都是在創建並運行一個進程。像Linux進程那樣,一個進程可以fork一個子進程,並讓這個子進程exec另外一個程序。在Python中,我們通過標准庫中的subprocess包來fork一個子進程,並運行一個外部的程序。
subprocess包中定義有數個創建子進程的函數,這些函數分別以不同的方式創建子進程,所以我們可以根據需要來從中選取一個使用。另外subprocess還提供了一些管理標准流(standard stream)和管道(pipe)的工具,從而在進程間使用文本通信。
subprocess.call()
父進程等待子進程完成
返回退出信息(returncode,相當於Linux exit code)
示例:
>>> a = subprocess.call(['df','-hT'],shell=False)
文件系統 類型 容量 已用 可用 已用% 掛載點
/dev/vda3 xfs 80G 3.6G 77G 5% /
devtmpfs devtmpfs 7.8G 0 7.8G 0% /dev
tmpfs tmpfs 7.8G 0 7.8G 0% /dev/shm
tmpfs tmpfs 7.8G 8.6M 7.8G 1% /run
tmpfs tmpfs 7.8G 0 7.8G 0% /sys/fs/cgroup
/dev/vda6 xfs 404G 2.2G 402G 1% /data1
/dev/vda2 xfs 497M 128M 370M 26% /boot
tmpfs tmpfs 1.5G 0 1.5G 0% /run/user/0
>>> print(a)
0 #程序返回的代碼值
>>> a = subprocess.call('aaaa',shell=True)
/bin/sh: aaaa: 未找到命令
>>>
subprocess.check_call()
subprocess.check_call(args, *, stdin = None, stdout = None, stderr = None, shell = False)
與call方法類似,不同在於如果命令行執行成功,check_call返回返回碼0,否則拋出subprocess.CalledProcessError異常。
subprocess.CalledProcessError異常包括returncode、cmd、output等屬性,其中returncode是子進程的退出碼,cmd是子進程的執行命令,output為None。
示例:
>>> import subprocess
>>> a = subprocess.check_call('df -h',shell=True)
文件系統 容量 已用 可用 已用% 掛載點
/dev/vda3 80G 3.6G 77G 5% /
devtmpfs 7.8G 0 7.8G 0% /dev
tmpfs 7.8G 0 7.8G 0% /dev/shm
tmpfs 7.8G 8.6M 7.8G 1% /run
tmpfs 7.8G 0 7.8G 0% /sys/fs/cgroup
/dev/vda6 404G 2.2G 402G 1% /data1
/dev/vda2 497M 128M 370M 26% /boot
tmpfs 1.2G 0 1.2G 0% /run/user/0
>>> print(a)
0
>>> a = subprocess.check_call('aaaa',shell=True)
/bin/sh: aaaa: 未找到命令
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/python3/lib/python3.6/subprocess.py", line 291, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command 'aaaa' returned non-zero exit status 127.
>>>
subprocess.check_output():
用法與上面兩個方法類似,區別是,如果當返回值為0時,直接返回輸出結果,如果返回值不為0,直接拋出異常
示例:
>>> a = subprocess.check_output(['df','-hT'],shell=False)
>>> print(a)
b'\xe6\x96\x87\xe4\xbb\xb6\xe7\xb3\xbb\xe7\xbb\x9f \xe7\xb1\xbb\xe5\x9e\x8b \xe5\xae\xb9\xe9\x87\x8f \xe5\xb7\xb2\xe7\x94\xa8 \xe5\x8f\xaf\xe7\x94\xa8 \xe5\xb7\xb2\xe7\x94\xa8% \xe6\x8c\x82\xe8\xbd\xbd\xe7\x82\xb9\n/dev/vda3 xfs 80G 3.6G 77G 5% /\ndevtmpfs devtmpfs 7.8G 0 7.8G 0% /dev\ntmpfs tmpfs 7.8G 0 7.8G 0% /dev/shm\ntmpfs tmpfs 7.8G 8.6M 7.8G 1% /run\ntmpfs tmpfs 7.8G 0 7.8G 0% /sys/fs/cgroup\n/dev/vda6 xfs 404G 2.2G 402G 1% /data1\n/dev/vda2 xfs 497M 128M 370M 26% /boot\ntmpfs tmpfs 1.5G 0 1.5G 0% /run/user/0\n'
>>> print(str(a.rstrip(),'utf-8'))
文件系統 類型 容量 已用 可用 已用% 掛載點
/dev/vda3 xfs 80G 3.6G 77G 5% /
devtmpfs devtmpfs 7.8G 0 7.8G 0% /dev
tmpfs tmpfs 7.8G 0 7.8G 0% /dev/shm
tmpfs tmpfs 7.8G 8.6M 7.8G 1% /run
tmpfs tmpfs 7.8G 0 7.8G 0% /sys/fs/cgroup
/dev/vda6 xfs 404G 2.2G 402G 1% /data1
/dev/vda2 xfs 497M 128M 370M 26% /boot
tmpfs tmpfs 1.5G 0 1.5G 0% /run/user/0
>>>
subprocess.Popen():
subprocess模塊定義了一個Popen類,通過它可以創建進程,並與其進行復雜的交互。
class Popen(args, bufsize=0, executable=None, stdin=None,stdout=None, stderr=None, preexec_fn=None, close_fds=False,
shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)
在一些復雜場景中,我們需要將一個進程的執行輸出作為另一個進程的輸入。在另一些場景中,我們需要先進入到某個輸入環境,然后再執行一系列的指令等。這個時候我們就需要使用到suprocess的Popen()方法。該方法有以下參數
參數 | 作用 |
---|---|
args | 一般是一個字符串,是要執行的shell命令內容 |
bufsize | 設置緩沖,負數表示系統默認緩沖,0表示無緩沖,正數表示自定義緩沖行數 |
stdin | 程序的標准輸入句柄,NONE表示不進行重定向,繼承父進程,PIPE表示創建管道 |
stdout | 程序的標准輸出句柄,參數意義同上 |
stderr | 程序的標准錯誤句柄,參數意義同上,特殊,可以設置成STDOUT,表示與標准輸出一致 |
shell | 為True時,表示將通過shell來執行 |
cwd | 用來設置當前子進程的目錄 |
env | 用於指定子進程的環境變量。如果env=None,則默認從父進程繼承環境變量 |
universal_newlines | 不同系統的的換行符不同,當該參數設定為true時,則表示使用\n作為換行符。 |
Popen方法:
- 1、Popen.poll():用於檢查子進程是否已經結束。設置並返回returncode屬性。
- 2、Popen.wait():等待子進程結束。設置並返回returncode屬性。
- 3、Popen.communicate(input=None):與子進程進行交互。向stdin發送數據,或從stdout和stderr中讀取數據。可選參數input指定發送到子進程的參數。Communicate()返回一個元組:(stdoutdata, stderrdata)。注意:如果希望通過進程的stdin向其發送數據,在創建Popen對象的時候,參數stdin必須被設置為PIPE。同樣,如果希望從stdout和stderr獲取數據,必須將stdout和stderr設置為PIPE。
- 4、Popen.send_signal(signal):向子進程發送信號。
- 5、Popen.terminate():停止(stop)子進程。在windows平台下,該方法將調用Windows API TerminateProcess()來結束子進程。
- 6、Popen.kill():殺死子進程。
- 7、Popen.stdin:如果在創建Popen對象是,參數stdin被設置為PIPE,Popen.stdin將返回一個文件對象用於策子進程發送指令。否則返回None。
- 8、Popen.stdout:如果在創建Popen對象是,參數stdout被設置為PIPE,Popen.stdout將返回一個文件對象用於策子進程發送指令。否則返回None。
- 9、Popen.stderr:如果在創建Popen對象是,參數stdout被設置為PIPE,Popen.stdout將返回一個文件對象用於策子進程發送指令。否則返回None。
- 10、Popen.pid:獲取子進程的進程ID。
- 11、Popen.returncode:獲取進程的返回值。如果進程還沒有結束,返回None。
- 12、subprocess.call(*popenargs, **kwargs):運行命令。該函數將一直等待到子進程運行結束,並返回進程的returncode。文章一開始的例子就演示了call函數。如果子進程不需要進行交互,就可以使用該函數來創建。
- 13、subprocess.check_call(popenargs, **kwargs):與subprocess.call(popenargs, **kwargs)功能一樣,只是如果子進程返回的returncode不為0的話,將觸發CalledProcessError異常。在異常對象中,包括進程的returncode信息
示例:
>>> import subprocess
>>> subprocess.Popen('/apps/apache-tomcat-8.5.29/bin/startup.sh',shell=True)
<subprocess.Popen object at 0x7f3579b2dfd0>
>>> Using CATALINA_BASE: /apps/apache-tomcat-8.5.29
Using CATALINA_HOME: /apps/apache-tomcat-8.5.29
Using CATALINA_TMPDIR: /apps/apache-tomcat-8.5.29/temp
Using JRE_HOME: /usr/java/jdk1.8.0_111/
Using CLASSPATH: /apps/apache-tomcat-8.5.29/bin/bootstrap.jar:/apps/apache-tomcat-8.5.29/bin/tomcat-juli.jar
Tomcat started.
>>> popen = subprocess.Popen('tail -f /apps/apache-tomcat-8.5.29/logs/catalina.out',shell=True)
>>> at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:1086)
at org.apache.tomcat.util.net.AbstractJsseEndpoint.init(AbstractJsseEndpoint.java:268)
at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:581)
at org.apache.catalina.connector.Connector.initInternal(Connector.java:993)
... 13 more
19-Nov-2019 17:05:05.020 信息 [main] org.apache.catalina.startup.Catalina.load Initialization processed in 650 ms
19-Nov-2019 17:05:05.045 信息 [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
19-Nov-2019 17:05:05.045 信息 [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.29
19-Nov-2019 17:05:05.061 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/apps/apache-tomcat-8.5.29/webapps/ROOT]
KeyboardInterrupt
>>> popen.terminate()
>>>
注意!
在shell=True這個參數,不寫的時候默認是False,shell默認為/bin/sh。如果 args是一個字符串,則該字符串指定要通過shell執行的命令。
當需要設置shell=True時(當False時,arges是列表,第一個參數是shell命令,后面的都是參數',' 隔開),須把args設為string,空格隔開,如下
>>> a = subprocess.Popen(['tail','-f', '/apps/apache-tomcat-8.5.29/logs/catalina.out'])
>>> a = subprocess.Popen('tail -f /apps/apache-tomcat-8.5.29/logs/catalina.out',shell=True)