1 os與commands模塊
2 subprocess模塊
3 subprocess.Popen類python
咱們幾乎能夠在任何操做系統上經過命令行指令與操做系統進行交互,好比Linux平臺下的shell。
那麼咱們如何經過Python來完成這些命令行指令的執行呢?另外,咱們應該知道的是命令行指令的
執行一般有兩個咱們比較關注的結果:linux
1 命令執行的狀態碼--表示命令執行是否成功
2 命令執行的輸出結果--命令執行成功後的輸出shell
早期的Python版本中,咱們主要是經過os.system()、os.popen().read()等函數來執行命令行指令的,另外還有一個不多使用的commands模塊。
可是從Python 2.4開始官方文檔中建議使用的是subprocess模塊,因此os模塊和commands模塊的相關函數在這裏只提供一個簡單的使用示例,咱們重要要介紹的是subprocess模塊。vim
1、os與commands模塊
Python中提供瞭如下幾個函數來幫助咱們完成命令行指令的執行:windows
函數名 描述
os.system(command) 返回命令執行狀態碼,而將命令執行結果輸出到屏幕python3.x
os.popen(command).read() 能夠獲取命令執行結果,可是沒法獲取命令執行狀態碼安全
commands.getstatusoutput(command) 返回一個元組(命令執行狀態碼, 命令執行結果)ide
os.popen(command)函數獲得的是一個文件對象,所以除了read()方法外還支持write()等方法,具體要根據command來定;函數
commands模塊只存在於Python 2.7中,且不支持windows平臺,所以commands模塊不多被使用。另外,commands模塊實際上也是經過對os.popen()的封裝來完成的。ui
import os
retcode = os.system('dir')
import os
ret = os.popen('dir').read()
print(ret)
須要注意的是commands模塊不支持windows平臺,所以該實例是在Linux平臺下執行的
import os
os.system('ls')
import commands
retcode, ret = commands.getstatusoutput('ls -l')
retcode
0
print(ret)
經過查看commands模塊提供的屬性可知,它也提供了單獨獲取命令執行狀態碼和執行結果的函數,以下所示:
dir(commands)
['all', 'builtins', 'doc', 'file', 'name', 'package', 'getoutput', 'getstatus', 'getstatusoutput', 'mk2arg', 'mkarg']
subprocess – 建立附加進程 ,subprocess是Python 2.4中新增的一個模塊,它容許你生成新的進程,鏈接到它們的 input/output/error 管道,並獲取它們的返回(狀態)碼。
subprocess模塊提供了一種一致的方法來建立和處理附加進程,與標準庫中的其它模塊相比,提供了一個更高級的接口。用於替換以下模塊:
os.system() , os.spawnv() , os和popen2模塊中的popen()函數,以及 commands().
函數 描述
subprocess.run() Python 3.5中新增的函數。執行指定的命令,等待命令執行完成後返回一個包含執行結果的CompletedProcess類的實例。
subprocess.call() 執行指定的命令,返回命令執行狀態,其功能相似於os.system(cmd)。
subprocess.check_call() Python 2.5中新增的函數。 執行指定的命令,若是執行成功則返回狀態碼,不然拋出異常。其功能等價於subprocess.run(..., check=True)。
subprocess.check_output() Python 2.7中新增的的函數。執行指定的命令,若是執行狀態碼爲0則返回命令執行結果,不然拋出異常。
subprocess.getoutput(cmd) 接收字符串格式的命令,執行命令並返回執行結果,其功能相似於os.popen(cmd).read()和commands.getoutput(cmd)。
subprocess.getstatusoutput(cmd) 執行cmd命令,返回一個元組(命令執行狀態, 命令執行結果輸出),其功能相似於commands.getstatusoutput()。
說明:
在Python 3.5以後的版本中,官方文檔中提倡經過subprocess.run()函數替代其餘函數來使用
subproccess模塊的功能;
在Python 3.5以前的版本中,咱們能夠經過subprocess.call(),subprocess.getoutput()等上面列出的其餘函數來使用subprocess模塊的功能;
subprocess.run()、subprocess.call()、subprocess.check_call()和subprocess.check_output()都是經過對subprocess.Popen的封裝來實現的高級函數,所以若是咱們須要更復雜功能時,能夠經過subprocess.Popen來完成。
subprocess.getoutput()和subprocess.getstatusoutput()函數是來自Python 2.x的commands模塊的兩個遺留函數。它們隱式的調用系統shell,而且不保證其餘函數所具備的安全性和異常處理的一致性。另外,它們從Python 3.3.4開始才支持Windows平臺。
函數參數列表:
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False, universal_newlines=False)
subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)
subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)
subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None)
subprocess.getstatusoutput(cmd)
subprocess.getoutput(cmd)
參數說明:
args: 要執行的shell命令,默認應該是一個字符串序列,如['df', '-Th']或('df', '-Th'),也能夠是一個字符串,如'df -Th',可是此時須要把shell參數的值置爲True。
shell: 若是shell爲True,那麼指定的命令將經過shell執行。若是咱們須要訪問某些shell的特性,如管道、文件名通配符、環境變量擴展功能,這將是很是有用的。固然,python自己也提供了許多相似shell的特性的實現,如glob、fnmatch、os.walk()、os.path.expandvars()、os.expanduser()和shutil等。
check: 若是check參數的值是True,且執行命令的進程以非0狀態碼退出,則會拋出一個CalledProcessError的異常,且該異常對象會包含 參數、退出狀態碼、以及stdout和stderr(若是它們有被捕獲的話)。
stdout, stderr:
run()函數默認不會捕獲命令執行結果的正常輸出和錯誤輸出,若是咱們向獲取這些內容須要傳遞subprocess.PIPE,而後能夠經過返回的CompletedProcess類實例的stdout和stderr屬性或捕獲相應的內容;
call()和check_call()函數返回的是命令執行的狀態碼,而不是CompletedProcess類實例,因此對於它們而言,stdout和stderr不適合賦值爲subprocess.PIPE;
check_output()函數默認就會返回命令執行結果,因此不用設置stdout的值,若是咱們但願在結果中捕獲錯誤信息,能夠執行stderr=subprocess.STDOUT。
input: 該參數是傳遞給Popen.communicate(),一般該參數的值必須是一個字節序列,若是universal_newlines=True,則其值應該是一個字符串。
universal_newlines: 該參數影響的是輸入與輸出的數據格式,好比它的值默認爲False,此時stdout和stderr的輸出是字節序列;當該參數的值設置爲True時,stdout和stderr的輸出是字符串。
須要說明的是,subprocess.run()函數是Python3.5中新增的一個高級函數,其返回值是一個subprocess.CompletedPorcess類的實例,所以,subprocess.completedPorcess類也是Python 3.5中才存在的。它表示的是一個已結束進程的狀態信息,
它所包含的屬性以下:
args: 用於加載該進程的參數,這多是一個列表或一個字符串
returncode: 子進程的退出狀態碼。一般狀況下,退出狀態碼爲0則表示進程成功運行了;一個負值-N表示這個子進程被信號N終止了
stdout: 從子進程捕獲的stdout。這一般是一個字節序列,若是run()函數被調用時指定
universal_newlines=True,則該屬性值是一個字符串。若是run()函數被調用時指定
stderr=subprocess.STDOUT,那麼stdout和stderr將會被整合到這一個屬性中,且stderr將會爲None
stderr: 從子進程捕獲的stderr。它的值與stdout同樣,是一個字節序列或一個字符串。若是stderr滅有被捕獲的話,它的值就爲None
check_returncode(): 若是returncode是一個非0值,則該方法會拋出一個CalledProcessError異常。
subprocess.run()
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"], stdout=subprocess.PIPE)
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')
subprocess.call()
subprocess.call(['ls', '-l'])
總用量 160
drwxr-xr-x 2 wader wader 4096 12月 7 2015 公共的
drwxr-xr-x 2 wader wader 4096 12月 7 2015 模板
drwxr-xr-x 2 wader wader 4096 12月 7 2015 視頻
drwxr-xr-x 2 wader wader 4096 12月 7 2015 圖片
drwxr-xr-x 2 wader wader 4096 12月 7 2015 文檔
drwxr-xr-x 2 wader wader 4096 4月 13 2016 下載
drwxr-xr-x 2 wader wader 4096 12月 7 2015 音樂
drwxr-xr-x 7 wader wader 4096 5月 26 2016 桌面
0
subprocess.call('ls -l', shell=True)
總用量 160
drwxr-xr-x 2 wader wader 4096 12月 7 2015 公共的
drwxr-xr-x 2 wader wader 4096 12月 7 2015 模板
drwxr-xr-x 2 wader wader 4096 12月 7 2015 視頻
drwxr-xr-x 2 wader wader 4096 12月 7 2015 圖片
drwxr-xr-x 2 wader wader 4096 12月 7 2015 文檔
drwxr-xr-x 2 wader wader 4096 4月 13 2016 下載
drwxr-xr-x 2 wader wader 4096 12月 7 2015 音樂
drwxr-xr-x 7 wader wader 4096 5月 26 2016 桌面
0
subprocess.call(['ls', '-l'], stdout=subprocess.DEVNULL)
0
subprocess.call(['ls', '-l', '/test'])
ls: 沒法訪問/test: 沒有那個文件或目錄
2
suprocess.check_call()
subprocess.check_call(['ls', '-l'])
總用量 160
drwxr-xr-x 2 wader wader 4096 12月 7 2015 公共的
drwxr-xr-x 2 wader wader 4096 12月 7 2015 模板
drwxr-xr-x 2 wader wader 4096 12月 7 2015 視頻
drwxr-xr-x 2 wader wader 4096 12月 7 2015 圖片
drwxr-xr-x 2 wader wader 4096 12月 7 2015 文檔
drwxr-xr-x 2 wader wader 4096 4月 13 2016 下載
drwxr-xr-x 2 wader wader 4096 12月 7 2015 音樂
drwxr-xr-x 7 wader wader 4096 5月 26 2016 桌面
0
subprocess.check_call('ls -l', shell=True)
總用量 160
drwxr-xr-x 2 wader wader 4096 12月 7 2015 公共的
drwxr-xr-x 2 wader wader 4096 12月 7 2015 模板
drwxr-xr-x 2 wader wader 4096 12月 7 2015 視頻
drwxr-xr-x 2 wader wader 4096 12月 7 2015 圖片
drwxr-xr-x 2 wader wader 4096 12月 7 2015 文檔
drwxr-xr-x 2 wader wader 4096 4月 13 2016 下載
drwxr-xr-x 2 wader wader 4096 12月 7 2015 音樂
drwxr-xr-x 7 wader wader 4096 5月 26 2016 桌面
0
subprocess.check_call('ls -l /test', shell=True)
ls: 沒法訪問/test: 沒有那個文件或目錄
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.4/subprocess.py", line 557, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command 'ls -l /test' returned non-zero exit status 2
sbuprocess.check_output()
ret = subprocess.check_output(['ls', '-l'])
print(ret)
b' \xe5\x85\xac\xe5\x85\xb1\xe7\x9a\x84\ndrwxr-xr-x 2 wader wader 4096 12\xe6\x9c\x88 7 2015 \xe6\xa8\xa1\xe6\x9d\xbf\ndrwxr-xr-x 2 wader wader 4096 12\xe6\x9c\x88 7 2015 \xe8\xa7\x86\xe9\xa2\x91\ndrwxr-xr-x 2 wader wader 4096 12\xe6\x9c\x88 7 2015 \xe5\x9b\xbe\xe7\x89\x87\ndrwxr-xr-x 2 wader wader 4096 12\xe6\x9c\x88 7 2015 \xe6\x96\x87\xe6\xa1\xa3\ndrwxr-xr-x 2 wader wader 4096 4\xe6\x9c\x88 13 2016 \xe4\xb8\x8b\xe8\xbd\xbd\ndrwxr-xr-x 2 wader wader 4096 12\xe6\x9c\x88 7 2015 \xe9\x9f\xb3\xe4\xb9\x90\ndrwxr-xr-x 7 wader wader 4096 5\xe6\x9c\x88 26 2016 \xe6\xa1\x8c\xe9\x9d\xa2\n'
ret = subprocess.check_output(['ls', '-l'], universal_newlines=True)
print(ret)
總用量 160
drwxr-xr-x 2 wader wader 4096 12月 7 2015 公共的
drwxr-xr-x 2 wader wader 4096 12月 7 2015 模板
drwxr-xr-x 2 wader wader 4096 12月 7 2015 視頻
drwxr-xr-x 2 wader wader 4096 12月 7 2015 圖片
drwxr-xr-x 2 wader wader 4096 12月 7 2015 文檔
drwxr-xr-x 2 wader wader 4096 4月 13 2016 下載
drwxr-xr-x 2 wader wader 4096 12月 7 2015 音樂
drwxr-xr-x 7 wader wader 4096 5月 26 2016 桌面
subprocess.getoutput()與subprocess.getstatusoutput()
ret = subprocess.getoutput('ls -l')
print(ret)
總用量 160
drwxr-xr-x 2 wader wader 4096 12月 7 2015 公共的
drwxr-xr-x 2 wader wader 4096 12月 7 2015 模板
drwxr-xr-x 2 wader wader 4096 12月 7 2015 視頻
drwxr-xr-x 2 wader wader 4096 12月 7 2015 圖片
drwxr-xr-x 2 wader wader 4096 12月 7 2015 文檔
drwxr-xr-x 2 wader wader 4096 4月 13 2016 下載
drwxr-xr-x 2 wader wader 4096 12月 7 2015 音樂
drwxr-xr-x 7 wader wader 4096 5月 26 2016 桌面
retcode, output = subprocess.getstatusoutput('ls -l')
print(retcode)
0
print(output)
總用量 160
drwxr-xr-x 2 wader wader 4096 12月 7 2015 公共的
drwxr-xr-x 2 wader wader 4096 12月 7 2015 模板
drwxr-xr-x 2 wader wader 4096 12月 7 2015 視頻
drwxr-xr-x 2 wader wader 4096 12月 7 2015 圖片
drwxr-xr-x 2 wader wader 4096 12月 7 2015 文檔
drwxr-xr-x 2 wader wader 4096 4月 13 2016 下載
drwxr-xr-x 2 wader wader 4096 12月 7 2015 音樂
drwxr-xr-x 7 wader wader 4096 5月 26 2016 桌面
retcode, output = subprocess.getstatusoutput('ls -l /test')
print(retcode)
2
print(output)
ls: 沒法訪問/test: 沒有那個文件或目錄
subprocess.call():執行命令,並返回執行狀態,其中shell參數爲False時,命令須要經過列表的方式傳入,當shell爲True時,可直接傳入命令
call()方法中的command能夠是一個列表,也能夠是一個字符串,做爲字符串時須要用原生的shell來執行:
import subprocess
#執行 df -hl 命令
#方法1:
subprocess.call(['ls','-l'])
total 8
drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
#方法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
如上實例所示,雖然咱們能看到執行的結果,但實際獲取的值只是狀態碼
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)
a = subprocess.call(['df','-hT'],shell=False)
Filesystem Type Size Used Avail Use% Mounted on
/dev/sda2 ext4 94G 64G 26G 72% /
tmpfs tmpfs 2.8G 0 2.8G 0% /dev/shm
/dev/sda1 ext4 976M 56M 853M 7% /boot
a = subprocess.call('df -hT',shell=True)
Filesystem Type Size Used Avail Use% Mounted on
/dev/sda2 ext4 94G 64G 26G 72% /
tmpfs tmpfs 2.8G 0 2.8G 0% /dev/shm
/dev/sda1 ext4 976M 56M 853M 7% /boot
print a
subprocess.check_call():用法與subprocess.call()相似,區別是,當返回值不爲0時,直接拋出異常
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
a = subprocess.check_call('df -hT',shell=True)
Filesystem Type Size Used Avail Use% Mounted on
/dev/sda2 ext4 94G 64G 26G 72% /
tmpfs tmpfs 2.8G 0 2.8G 0% /dev/shm
/dev/sda1 ext4 976M 56M 853M 7% /boot
print a
0
a = subprocess.check_call('dfdsf',shell=True)
/bin/sh: dfdsf: command not found
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python2.6/subprocess.py", line 502, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command 'dfdsf' returned non-zero exit status 127
subprocess.check_output():用法與上面兩個方法相似,區別是,若是當返回值爲0時,直接返回輸出結果,若是返回值不爲0,直接拋出異常。須要說明的是,該方法在python3.x中才有。
call()方法啓動的進程,其標準輸入輸出會綁定到父進程的輸入和輸出。調用程序沒法獲取命令的輸出結果。但能夠經過check_output()方法來捕獲輸出。
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傳遞不一樣的參數。
subprocess.Popen():
在一些複雜場景中,咱們須要將一個進程的執行輸出做爲另外一個進程的輸入。在另外一些場景中,咱們須要先進入到某個輸入環境,而後再執行一系列的指令等。這個時候咱們就須要使用到suprocess的Popen()方法。該方法有如下參數:
args:shell命令,能夠是字符串,或者序列類型,如list,tuple。
bufsize:緩衝區大小,可不用關心
stdin,stdout,stderr:分別表示程序的標準輸入,標準輸出及標準錯誤
shell:與上面方法中用法相同
cwd:用於設置子進程的當前目錄
env:用於指定子進程的環境變量。若是env=None,則默認從父進程繼承環境變量
universal_newlines:不一樣系統的的換行符不一樣,當該參數設定爲true時,則表示使用\n做爲換行符
示例1,在/root下建立一個suprocesstest的目錄:
a = subprocess.Popen('mkdir subprocesstest',shell=True,cwd='/root')
示例2,使用python執行幾個命令:
import subprocess
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
obj.stdin.write('print 1 \n')
obj.stdin.write('print 2 \n')
obj.stdin.write('print 3 \n')
obj.stdin.write('print 4 \n')
obj.stdin.close()
cmd_out = obj.stdout.read()
obj.stdout.close()
cmd_error = obj.stderr.read()
obj.stderr.close()
print cmd_out
print cmd_error
也可使用以下方法:
import subprocess
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
obj.stdin.write('print 1 \n')
obj.stdin.write('print 2 \n')
obj.stdin.write('print 3 \n')
obj.stdin.write('print 4 \n')
out_error_list = obj.communicate()
print out_error_list
示例3,將一個子進程的輸出,做爲另外一個子進程的輸入:
import subprocess
child1 = subprocess.Popen(["cat","/etc/passwd"], stdout=subprocess.PIPE)
child2 = subprocess.Popen(["grep","0:0"],stdin=child1.stdout, stdout=subprocess.PIPE)
out = child2.communicate()
其餘方法:
import subprocess
child = subprocess.Popen('sleep 60',shell=True,stdout=subprocess.PIPE)
child.poll() #檢查子進程狀態
child.kill() #終止子進程
child.send_signal() #向子進程發送信號
child.terminate() #終止子進程
與進程的單向通訊
經過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)
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
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)
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其它方法
Popen.pid 查看子進程ID
Popen.returncode 獲取子進程狀態碼,0表示子進程結束,None未結束
在使用Popen調用系統命令式,建議使用communicate與stdin進行交互並獲取輸出(stdout),這樣能保證子進程正常退出而避免出現殭屍進程。看下面例子
proc = subprocess.Popen('ls -l', shell=True, stdout=subprocess.PIPE)
proc.pid
28906
print(proc.returncode)
None
out_value = proc.communicate()
proc.pid
28906
print(proc.returncode)
0
1.subprocess模塊,
res = os.system('dir') 打印到屏幕,res爲0或非0
os.popen('dir') 返回一個內存對象,至關於文件流
a = os.popen('dir').read() a中就存的是執行結果輸出了
Python2.7 commands模塊 commands.getstatusoutput('dir')返回元祖,第一個元素爲狀態0爲成功,第二個爲結果windows上很差用,只是Linux好用
subprocess模塊,替換os.system等
subprocess.run(['df','-h']) 當參數傳,Python解析,若是有管道符就不行了
subprocess.run('df -h | grep sda1', shell=True) shell=True是指不須要Python解析,直接把字符串給shell
Python3.5纔出現subprocess.run
終端輸入的命令分爲兩種:
輸入便可獲得輸出,如:ifconfig
輸入進行某環境,依賴再輸入,如:Python
經常使用subprocess
沒有管道
retcode = subprocess.call(['ls','-l']) 成功返回0,不成功返回非0
subprocess.check_call(['ls','-l']) 執行成功返回0,執行錯誤拋異常
subprocess.getoutput('ls /bin/ls')接收字符串格式命令,只返回結果
res = subprocess.check_output(['ls','-l'])執行成功返回執行結果,不成功出錯
subprocess.getstatsoutput('ls /bin/ls') 返回元祖(1,'/bin/ls'),第一個狀態,第二個結果
上面的方法,底層都是封裝subprocess.popen
例子
res = subprocess.popen('ifconfig | grep 192',shell=True)
res
<subprocess.popen object at ox7f2131a>
res.stdout.read()讀不出來
要讀出來要先輸出到標準輸出裏,先存到管道PIPE 再給stdout python和shell是兩個進程不能獨立通訊,必須經過操做系統提供的管道
用管道能夠把結果存到stdin stdout stderr
subprocess.popen('ifconfig | grep 192',shell=True,stdout=subprocess.PIPE)
res.stdout.read()就能夠讀出來了
subprocess.popen('ifconfig | gr1111ep 192',shell=True,stdout=subprocess.PIPE)
出錯會直接打印錯誤。想不打印錯誤能夠stderr保存stderr=subprocess.PIPE
terminate()殺掉該進程,res.terminate()
wait() wait for child process to terminate. returns returncode attribute
communicate()等待任務結束 沒什麼用,用Python當參數,輸Python進入環境
stdin 標準輸入
stdout 標準輸出
stderr 標準錯誤
pid the process ID of the child process
-----可用參數
args: shell命令,能夠是字符串或者序列類型
bufsize:指定緩衝,0無緩衝,1 行緩衝,其餘 緩衝區大小 負值 系統緩衝
stdin,stdout,stderr:標準輸入,輸出,錯誤句柄
preexec_fn:只在Unix平臺下有效,用於指定一個可執行對象,它將在子進程運行以前被調用
close_sfs:在Windows平臺下,若是close_sfs被設置爲True,則新建立的子進程將不會繼承父進程的輸入、輸出、錯誤管道
因此不能將close_fds設置爲True同時重定向子進程的標準輸入、輸出與錯誤
shell:同上
cod:用於設置子進程的當前目錄
env:用於指定子進程的環境變量。若是env=None,子進程的環境變量將從父進程中繼承
universal_newlines:不一樣系統的換行符不一樣,True->贊成使用\n
startupinfo與createionflags只在Windows下有效
將被傳遞給底層的createprocess()函數,用於設置子進程的一些屬性,
如:主窗口的外觀,進程的優先級等
subprocess實現sudo自動輸入密碼
例如Python裏面執行sudo apt-get install vim (Linux裏面要輸入密碼)
linux中應該echo '123' | sudo -S iptables -L
python直接 subprocess.popen("echo '123' | sudo -S iptables -L",shell=True)
subprocess.Popen使用實例
實例1:
import subprocess
p = subprocess.Popen('df -Th', stdout=subprocess.PIPE, shell=True)
print(p.stdout.read())
Filesystem Type Size Used Avail Use% Mounted on
/dev/vda1 ext4 40G 12G 26G 31% /
devtmpfs devtmpfs 3.9G 0 3.9G 0% /dev
tmpfs tmpfs 3.9G 0 3.9G 0% /dev/shm
tmpfs tmpfs 3.9G 386M 3.5G 10% /run
tmpfs tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
tmpfs tmpfs 783M 0 783M 0% /run/user/0
tmpfs tmpfs 783M 0 783M 0% /run/user/1000
實例2:
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
obj.stdin.write('print(1) \n')
obj.stdin.write('print(2) \n')
obj.stdin.write('print(3) \n')
out,err = obj.communicate()
print(out)
1
2
3
print(err)
實例3:
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out,err = obj.communicate(input='print(1) \n')
print(out)
1
print(err)
實例4:
實現相似df -Th | grep data命令的功能,實際上就是實現shell中管道的共功能。
p1 = subprocess.Popen(['df', '-Th'], stdout=subprocess.PIPE)
p2 = subprocess.Popen(['grep', 'data'], stdin=p1.stdout, stdout=subprocess.PIPE)
out,err = p2.communicate()
print(out)
/dev/vdb1 ext4 493G 4.8G 463G 2% /data
/dev/vdd1 ext4 1008G 420G 537G 44% /data1
/dev/vde1 ext4 985G 503G 432G 54% /data2
print(err)
None
4、總結
那麼咱們到底該用哪一個模塊、哪一個函數來執行命令與系統及系統進行交互呢?下面咱們來作個總結:
首先應該知道的是,Python2.4版本引入了subprocess模塊用來替換os.system()、os.popen()、os.spawn*()等函數以及commands模塊;也就是說若是你使用的是Python 2.4及以上的版本就應該使用subprocess模塊了。若是你的應用使用的Python 2.4以上,可是是Python 3.5如下的版本,Python官方給出的建議是使用subprocess.call()函數。Python 2.5中新增了一個subprocess.check_call()函數,Python 2.7中新增了一個subprocess.check_output()函數,這兩個函數也能夠按照需求進行使用。若是你的應用使用的是Python 3.5及以上的版本(目前應該還不多),Python官方給出的建議是儘可能使用subprocess.run()函數。當subprocess.call()、subprocess.check_call()、subprocess.check_output()和subprocess.run()這些高級函數沒法知足需求時,咱們可使用subprocess.Popen類來實現咱們須要的複雜功能。