python的subprocess模塊

1 os與commands模塊

2 subprocess模塊

3 subprocess.Popen類

我們幾乎可以在任何操作系統上通過命令行指令與操作系統進行交互,比如Linux平臺下的shell。

​那麼我們如何通過Python來完成這些命令行指令的執行呢?另外,我們應該知道的是命令行指令的

​執行通常有兩個我們比較關注的結果:

1 命令執行的狀態碼--表示命令執行是否成功

2 命令執行的輸出結果--命令執行成功後的輸出

早期的Python版本中,我們主要是通過os.system()、os.popen().read()等函數來執行命令行指令的,另外還有一個很少使用的commands模塊。

​但是從Python 2.4開始官方文檔中建議使用的是subprocess模塊,所以os模塊和commands模塊的相關函數在這裏只提供一個簡單的使用示例,我們重要要介紹的是subprocess模塊。

一、os與commands模塊

Python中提供了以下幾個函數來幫助我們完成命令行指令的執行:

函數名 描述
os.system(command) 返回命令執行狀態碼,而將命令執行結果輸出到屏幕

os.popen(command).read() 可以獲取命令執行結果,但是無法獲取命令執行狀態碼

commands.getstatusoutput(command) 返回一個元組(命令執行狀態碼, 命令執行結果)

os.popen(command)函數得到的是一個文件對象,因此除了read()方法外還支持write()等方法,具體要根據command來定;

commands模塊只存在於Python 2.7中,且不支持windows平臺,因此commands模塊很少被使用。另外,commands模塊實際上也是通過對os.popen()的封裝來完成的。

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().

  1. subprocess模塊中的常用函數

函數 描述
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的輸出是字符串。

  1. subprocess.CompletedProcess類介紹

需要說明的是,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: 沒有那個文件或目錄

  1. 運行外部命令
    subprocess.call(command) 方法

    subprocess的call方法可以用於執行一個外部命令,但該方法不能返回執行的結果,只能返回執行的狀態碼: 成功(0) 或 錯誤(非0)

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


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

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


0

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)

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

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其它方法

Popen.pid 查看子進程ID
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

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

poll() check if child process has terminated. returns returncode

res=subprocess.popen("sleep 10;echo 'hello'", shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
執行的時候沒反應,不知道是卡主了還是執行完了
每次調subprocess執行Linux命令,都相當於啓動了一個新的shell,啓動新的進程,執行一次命令等結果
如果該命令要花半小時,不知道是卡主了還是執行完了,可以res.poll()返回none表示還沒有執行完,返回0表示執行完了
res.wait()等待結束然後返回0

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
四、總結
那麼我們到底該用哪個模塊、哪個函數來執行命令與系統及系統進行交互呢?下面我們來做個總結:

首先應該知道的是,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類來實現我們需要的複雜功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章