subprocess模塊允許你啟動一個新的進程,連接輸入/輸出/錯誤的管道,
獲得子進程的返回碼。這個模塊目標是代替一些老的模塊,比如os.system和os.spawn.
0x01 常見subprocess方法
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()。 |
subprocess.
run
(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False)
args 該參數用於啟動進程。這可能是一個列表或一個字符串。returncode 該參數表示子進程的退出狀態。通常情況下,0作為退出狀態表明它成功運行。負值-N表明子進程被信號N終止(僅POSIX)。stdout 該參數表示標准輸出
此調用方式返回CompletedProcess實例,和直接Popen 差不多,實現是一樣的,實際也是調用Popen,與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"], 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()
執行由參數提供的命令.
我們可以用數組作為參數運行命令,也可以用字符串作為參數運行命令(通過設置參數shell=True
)
注意,參數shell
默認為False
subprocess.call(['ipconfig','/all'])
subprocess.call('ipconfig /all',shell=True)
subprocess.getoutput(cmd)
cmd可以直接執行shell命令,而不需要cmd命令以列表輸入---subprocess.getoutput("cat /proc/meminfo")
返回值包含cmd的執行結果,可以直接賦值給某個變量
功能和getstatusoutput類似
a=subprocess.getoutput('ipconfig /all') print(a)
subprocess.getstatusoutput(cmd)
cmd可以直接執行shell命令,而不需要cmd命令以列表輸入----subprocess.getstatusoutput("cat /proc/meminfo")
返回值包含cmd的執行狀態和執行結果,可以直接賦值給某個變量,返回的是一個元組
a=subprocess.getstatusoutput('ipconfig /all') print(a)
subprocess.check_call()
check_call基本和call功能一樣,只是增加了返回狀態碼校驗,如果執行狀態碼是0,則返回0,否則拋出異常
subprocess.check_call(['ipconfig', '/all'])
subprocess.check_output()
執行命令,如果狀態碼是0,則返回執行結果,否則拋出異常--
a=subprocess.check_output(['ipconfig', '/all']) print(a)
0x02、subprocess.Popen()類
該類用於在一個新的進程中執行一個子程序。前面我們提到過,上面介紹的這些函數都是基於subprocess.Popen類實現的,通過使用這些被封裝后的高級函數可以很方面的完成一些常見的需求。由於subprocess模塊底層的進程創建和管理是由Popen類來處理的,因此,當我們無法通過上面哪些高級函數來實現一些不太常見的功能時就可以通過subprocess.Popen類提供的靈活的api來完成。
1.subprocess.Popen的構造函數
def __init__(self, args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *, encoding=None, errors=None)
參數說明:
- args: 要執行的shell命令,可以是字符串,也可以是命令各個參數組成的序列。當該參數的值是一個字符串時,該命令的解釋過程是與平台相關的,因此通常建議將args參數作為一個序列傳遞。
- bufsize: 指定緩存策略,0表示不緩沖,1表示行緩沖,其他大於1的數字表示緩沖區大小,負數 表示使用系統默認緩沖策略。
- stdin, stdout, stderr: 分別表示程序標准輸入、輸出、錯誤句柄。
- preexec_fn: 用於指定一個將在子進程運行之前被調用的可執行對象,只在Unix平台下有效。
- close_fds: 如果該參數的值為True,則除了0,1和2之外的所有文件描述符都將會在子進程執行之前被關閉。
- shell: 該參數用於標識是否使用shell作為要執行的程序,如果shell值為True,則建議將args參數作為一個字符串傳遞而不要作為一個序列傳遞。
- cwd: 如果該參數值不是None,則該函數將會在執行這個子進程之前改變當前工作目錄。
- env: 用於指定子進程的環境變量,如果env=None,那么子進程的環境變量將從父進程中繼承。如果env!=None,它的值必須是一個映射對象。
- universal_newlines: 如果該參數值為True,則該文件對象的stdin,stdout和stderr將會作為文本流被打開,否則他們將會被作為二進制流被打開。
- startupinfo和creationflags: 這兩個參數只在Windows下有效,它們將被傳遞給底層的CreateProcess()函數,用於設置子進程的一些屬性,如主窗口的外觀,進程優先級等。
2. subprocess.Popen類的實例可調用的方法
方法 | 描述 |
---|---|
Popen.poll() | 用於檢查子進程(命令)是否已經執行結束,沒結束返回None,結束后返回狀態碼。 |
Popen.wait(timeout=None) | 等待子進程結束,並返回狀態碼;如果在timeout指定的秒數之后進程還沒有結束,將會拋出一個TimeoutExpired異常。 |
Popen.communicate(input=None, timeout=None) | 該方法可用來與進程進行交互,比如發送數據到stdin,從stdout和stderr讀取數據,直到到達文件末尾。 |
Popen.send_signal(signal) | 發送指定的信號給這個子進程。 |
Popen.terminate() | 停止該子進程。 |
Popen.kill() | 殺死該子進程。 |
關於communicate()方法的說明:
- 該方法中的可選參數 input 應該是將被發送給子進程的數據,或者如沒有數據發送給子進程,該參數應該是None。input參數的數據類型必須是字節串,如果universal_newlines參數值為True,則input參數的數據類型必須是字符串。
- 該方法返回一個元組(stdout_data, stderr_data),這些數據將會是字節穿或字符串(如果universal_newlines的值為True)。
- 如果在timeout指定的秒數后該進程還沒有結束,將會拋出一個TimeoutExpired異常。捕獲這個異常,然后重新嘗試通信不會丟失任何輸出的數據。但是超時之后子進程並沒有被殺死,為了合理的清除相應的內容,一個好的應用應該手動殺死這個子進程來結束通信。
- 需要注意的是,這里讀取的數據是緩沖在內存中的,所以,如果數據大小非常大或者是無限的,就不應該使用這個方法。
3. 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