subprocess模塊
subprocess – 創建附加進程
subprocess模塊提供了一種一致的方法來創建和處理附加進程,與標準庫中的其它模塊相比,提供了一個更高級的接口。用於替換如下模塊:
os.system() , os.spawnv() , os和popen2模塊中的popen()函數,以及 commands().
1. 運行外部命令
subprocess.call(command) 方法
subprocess的call方法可以用於執行一個外部命令,但該方法不能返回執行的結果,只能返回執行的狀態碼: 成功(0) 或 錯誤(非0)
call()方法中的command可以是一個列表,也可以是一個字符串,作為字符串時需要用原生的shell來執行:
import subprocess
#執行 df -hl 命令
#方法1:
>>> subprocess.call([‘ls‘,‘-l‘])=subprocess.run("ls -l") #python3以後
total 8
drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
0
#方法2:
>>> subprocess.call("ls -l",shell=True)
total 8
drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
0
如上實例所示,雖然我們能看到執行的結果,但實際獲取的值只是狀態碼
>>> output = subprocess.call("ls -l",shell=True)
total 8
drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
>>> print(output)
0
2. 錯誤處理
subprocess.check_call()
我們說過call執行返回一個狀態碼,我們可以通過check_call()函數來檢測命令的執行結果,如果不成功將返回 subprocess.CalledProcessError 異常
>>> try:
subprocess.check_call("ls -t", shell=True)
except subprocess.CalledProcessError as err:
print("Command Error")
/bin/sh: lt: command not found
Command Error
3. 捕獲輸出結果
subprocess.check_output() 方法
call()方法啟動的進程,其標準輸入輸出會綁定到父進程的輸入和輸出。調用程序無法獲取命令的輸出結果。但可以通過check_output()方法來捕獲輸出。
# 以下測試為python3.4下運行結果
>>> output=subprocess.check_output("ls -l",shell=True)
>>> output
b‘total 8\ndrwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem\ndrwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp\n‘
>>> print(output.decode(‘utf-8‘))
total 8
drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
以下例子將chek_output()方法執行命令異常時的錯誤捕獲,而避免輸出到控制臺.
try:
output = subprocess.check_output("lT -l", shell=True, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as err:
print("Command Error", err)
# 執行結果
Command Error Command ‘lT -l‘ returned non-zero exit status 127
直接處理管道
subprocess.Popen()方法
函數call(), check_call() 和 check_output() 都是Popen類的包裝器。直接使用Popen會對如何運行命令以及如何處理其輸入輸出有更多控制。如通過為stdin, stdout和stderr傳遞不同的參數。
1. 與進程的單向通信
通過Popen()方法調用命令後執行的結果,可以設置stdout值為PIPE,再調用communicate()獲取結果
返回結果為tuple. 在python3中結果為byte類型,要得到str類型需要decode轉換一下
輸出結果(讀)
# 直接執行命令輸出到屏幕
>>> subprocess.Popen("ls -l",shell=True)
<subprocess.Popen object at 0x7febd4175198>
>>> total 12
drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
-rw-rw-r-- 1 ws ws 8 Feb 25 10:38 test
drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
# 不輸出到屏幕,輸出到變量
>>> proc = subprocess.Popen([‘echo‘,‘"Stdout"‘],stdout=subprocess.PIPE)
# communicate返回標準輸出或標準出錯信息
>>> stdout_value = proc.communicate()
>>> stdout_value
(b‘"Stdout"\n‘, None)
>>> proc = subprocess.Popen([‘ls‘,‘-l‘],stdout=subprocess.PIPE)
>>> stdout_value = proc.communicate()
>>> stdout_value
(b‘total 8\ndrwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem\ndrwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp\n‘, None)
>>>
>>> print((stdout_value[0]).decode(‘utf-8‘))
total 8
drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
#將結果輸出到文件
>>> file_handle = open("/home/ws/t.log",‘w+‘)
>>> subprocess.Popen("ls -l",shell=True,stdout=file_handle)
t.log:
drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
-rw-rw-r-- 1 ws ws 8 Feb 25 10:38 test
-rw-rw-r-- 1 ws ws 0 Feb 25 11:24 t.log
drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
2 與進程的雙向通信
>>> proc = subprocess.Popen(‘cat‘, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
>>> msg = ‘Hello world‘.encode(‘utf-8‘)
# 寫入到輸入管道
>>> proc.stdin.write(msg)
11
>>> stdout_value = proc.communicate()
>>> stdout_value
(b‘Hello world‘, None)
# 在需要進行相互交互的輸入輸出過程也可以使用shtin來實現
# 以下實現打開python3的終端,執行一個print命令
>>>proc = subprocess.Popen([‘python3‘],stdin=subprocess.PIPE,stdout=subprocess.PIPE, stderr=subprocess.PIPE,)
>>>proc.stdin.write(‘print("helloworld")‘.encode(‘utf-8‘))
>>>out_value,err_value=proc.communicate()
>>>print(out_value)
>>> print(out_value)
b‘helloworld\n‘
>>> print(err_value)
b‘‘
Popen.communicate()方法用於和子進程交互:發送數據到stdin,並從stdout和stderr讀數據,直到收到EOF。等待子進程結束。
捕獲錯誤輸出
>>> proc = subprocess.Popen([‘python3‘],stdin=subprocess.PIPE,stdout=subprocess.PIPE, stderr=subprocess.PIPE,)
>>> proc.stdin.write(‘print "helloworld"‘.encode(‘utf-8‘))
18
>>> out_value,err_value=proc.communicate()
>>> out_value
b‘‘
>>> print(err_value.decode(‘utf-8‘))
File "<stdin>", line 1
print "helloworld"
^
SyntaxError: Missing parentheses in call to ‘print‘
Popen其它方法
1. Popen.pid 查看子進程ID
2. Popen.returncode 獲取子進程狀態碼,0表示子進程結束,None未結束
在使用Popen調用系統命令式,建議使用communicate與stdin進行交互並獲取輸出(stdout),這樣能保證子進程正常退出而避免出現僵屍進程。看下面例子
>>> proc = subprocess.Popen(‘ls -l‘, shell=True, stdout=subprocess.PIPE)
# 當前子進程ID
>>> proc.pid
28906
# 返回狀態為None,進程未結束
>>> print(proc.returncode)
None
# 通過communicate提交後
>>> out_value = proc.communicate()
>>> proc.pid
28906
# 返回狀態為0,子進程自動結束
>>> print(proc.returncode)
0
subprocess模塊