python之commands和subprocess入門介紹(可執行shell命令的模塊)


一、commands模塊

1、介紹

當我們使用Python進行編碼的時候,但是又想運行一些shell命令,去創建文件夾、移動文件等等操作時,我們可以使用一些Python庫去執行shell命令。

commands模塊就是其中的一個可執行shell命令的庫,commands模塊是python的內置模塊,共有三個函數:

  1. getstatus(file):返回執行 ls -ld file 命令的結果( -ld 代表的是僅列出指定目錄的詳細信息)。
  2. getoutput(cmd):執行cmd命令,並返回輸出的內容,返回結果為str。
  3. getstatusoutput(cmd):執行cmd命令,並返回執行的狀態(status)和輸出的內容(output),status代表的shell命令的返回狀態,如果成功的話是0,output是shell的返回的結果。

 

注意:

commands從2.6版開始不推薦使用:模塊已在Python 3中刪除。推薦使用subprocess模塊(等下再介紹)。

在3.x版本中,getstatus()方法被移除,getoutput()和getstatusoutput()被放到了subprocess模塊中。

 

2、getstatus(file)

返回執行 ls -ld file 命令的結果( -ld 代表的是僅列出指定目錄的詳細信息)。

# -*- coding: utf-8 -*-
import commands
status = commands.getstatus("/opt")  # 即執行了:ls -ld /opt
print status


# 結果
drwxr-xr-x. 9 root root 4096 2019/11/11 16:49:40 /opt

 

3、getoutput(cmd)

執行cmd命令,並返回輸出的內容,返回結果為str。

# -*- coding: utf-8 -*-
import commands
output = commands.getoutput("ls -l /opt")
print output


# 結果
總用量 28
drwx--x--x  4 root root 4096 2019/11/11 16:49:40 containerd
drwxr-xr-x 13 root root 4096 2019/01/15 14:48:15 nginx1.12
drwxrwxr-x  7  500  500 4096 2019/01/14 10:30:05 node-v8.6.0-linux-x64
drwxr-xr-x  7 root root 4096 2019/09/17 09:31:24 Projects
drwxr-xr-x  6 root root 4096 2019/01/10 19:17:30 python36
drwxrwxr-x  8 root root 4096 2019/09/16 20:00:52 redis-4.0.10
drwxr-xr-x  6 root root 4096 2019/01/16 17:47:34 ruby

 

4、getstatusoutput(cmd)

 執行cmd命令,並返回執行的狀態(status)和輸出的內容(output),status代表的shell命令的返回狀態,如果成功的話是0,output是shell的返回的結果。

# -*- coding: utf-8 -*-
import commands
status, output = commands.getstatusoutput("ls -l /opt")
print "status: %s" % status
print "output: %s" % output


# 結果
status: 0
output: 總用量 28
drwx--x--x  4 root root 4096 2019/11/11 16:49:40 containerd
drwxr-xr-x 13 root root 4096 2019/01/15 14:48:15 nginx1.12
drwxrwxr-x  7  500  500 4096 2019/01/14 10:30:05 node-v8.6.0-linux-x64
drwxr-xr-x  7 root root 4096 2019/09/17 09:31:24 Projects
drwxr-xr-x  6 root root 4096 2019/01/10 19:17:30 python36
drwxrwxr-x  8 root root 4096 2019/09/16 20:00:52 redis-4.0.10
drwxr-xr-x  6 root root 4096 2019/01/16 17:47:34 ruby

 

 二、subprocess模塊

1、介紹

subprocess模塊允許你啟動一個新的進程,連接輸入/輸出/錯誤的管道, 獲得子進程的返回碼。這個模塊目標是代替一些老的模塊,比如os.system和os.spawn。

subprocess模塊中的常用函數

函數 描述
subprocess.getoutput(cmd) 接收字符串格式的命令,執行命令並返回執行結果,其功能類似於os.popen(cmd).read()和commands.getoutput(cmd)。
subprocess.getstatusoutput(cmd) 執行cmd命令,返回一個元組(命令執行狀態, 命令執行結果輸出),其功能類似於commands.getstatusoutput()。
subprocess.call() 執行指定的命令,返回命令執行狀態,其功能類似於os.system(cmd)。
subprocess.check_call() Python 2.5中新增的函數。 執行指定的命令,如果執行成功則返回狀態碼,否則拋出異常。其功能等價於subprocess.run(..., check=True)。
subprocess.check_output() Python 2.7中新增的的函數。執行指定的命令,如果執行狀態碼為0則返回命令執行結果,否則拋出異常。
subprocess.run() Python 3.5中新增的函數。執行指定的命令,等待命令執行完成后返回一個包含執行結果的CompletedProcess類的實例。

 

2、getoutput,getstatusoutput

上面我們說了,commands在3.x版本中,getstatus()方法被移除,getoutput()和getstatusoutput()被放到了subprocess模塊中。

因此subprocess中的getoutput,getstatusoutput用法與commands的用法一模一樣。

# -*- coding: utf-8 -*-
import subprocess
output = subprocess.getoutput("pwd")
print("output1: %s" % output)

status, output = subprocess.getstatusoutput("pwd")
print("status2: %s" % status)
print("output2: %s" % output)


# 結果
output1: /tmp

status2: 0
output2: /tmp

 

3、subprocess.call()

返回值為命令執行狀態碼;
若未指定stdout,則命令執行后的結果輸出到屏幕;
若指定stdout,則命令執行后的結果輸出到stdout;
若執行成功,則函數返回值為0;若執行失敗,則函數返回值為1;

執行命令,輸出到屏幕(終端),返回狀態碼(命令正常執行返回0,其他狀態碼都是錯誤狀態碼)

subprocess.call(cmd,[shell=False,stdout]) 當shell=False的時候(默認),cmd為一個列表,當shell=True的時候,cmd為一個字符串,例如:

# -*- coding:utf-8 -*-
import subprocess

try:
    # shell=False
    ret1 = subprocess.call(["ls", "-l", "/opt"], shell=False)
    print("result1: %s" % ret1)

    # shell=True
    ret2 = subprocess.call("lxxs -l /tmp", shell=True)  # 當命令是錯誤的時候,返回的狀態碼就不是0了
    print("result2: %s" % ret2)
except Exception as e:
    print(e)

# 結果
總用量 28
drwx--x--x  4 root root 4096 2019/11/11 16:49:40 containerd
drwxr-xr-x 13 root root 4096 2019/01/15 14:48:15 nginx1.12
drwxrwxr-x  7  500  500 4096 2019/01/14 10:30:05 node-v8.6.0-linux-x64
drwxr-xr-x  7 root root 4096 2019/09/17 09:31:24 Projects
drwxr-xr-x  6 root root 4096 2019/01/10 19:17:30 python36
drwxrwxr-x  8 root root 4096 2019/09/16 20:00:52 redis-4.0.10
drwxr-xr-x  6 root root 4096 2019/01/16 17:47:34 ruby
result1: 0

/bin/sh: lxxs: 未找到命令
result2: 127

 

4、subprocess.check_call()

返回值為命令執行狀態碼;
若未指定stdout,則命令執行后的結果輸出到屏幕;
若指定stdout,則命令執行后的結果輸出到stdout;
若執行成功,則函數返回值為0;若執行失敗,拋出異常;

執行命令,輸出到屏幕(終端),如果執行成功則返回狀態碼0,否則拋異常(subprocess.CalledProcessError)。

其實check_call基本和call功能一樣,只是增加了返回狀態碼校驗,如果執行狀態碼是0,則返回0,否則拋出異常

# -*- coding:utf-8 -*-
import subprocess

try:
    ret = subprocess.check_call("ls -l /opt", shell=True)
    print("result: %s" % ret)
except subprocess.CalledProcessError as e:
    print(e)

 

5、subprocess.check_output()

返回值為命令執行的輸出結果;
若執行成功,則函數返回值為命令輸出結果;若執行失敗,則拋出異常;

執行命令,不會輸出到屏幕(終端),如果執行成功則返回執行結果,否則拋異常

# -*- coding:utf-8 -*-
import subprocess

try:
    ret = subprocess.check_output("ls -l /opt", shell=True)
    print("result: %s" % ret)
except subprocess.CalledProcessError as e:
    print(e)


# 結果
result: b'\xe6\x80\xbb\xe7\x94\xa8\xe9\x87\x8f 28\ndrwx--x--x  4 root root 4096 2019/11/11 16:49:40 containerd\ndrwxr-xr-x 13 root root 4096 2019/01/15 14:48:15 nginx1.12\ndrwxrwxr-x  7  500  500 4096 2019/01/14 10:30:05 node-v8.6.0-linux-x64\ndrwxr-xr-x  7 root root 4096 2019/09/17 09:31:24 Projects\ndrwxr-xr-x  6 root root 4096 2019/01/10 19:17:30 python36\ndrwxrwxr-x  8 root root 4096 2019/09/16 20:00:52 redis-4.0.10\ndrwxr-xr-x  6 root root 4096 2019/01/16 17:47:34 ruby\n'

 

6、subprocess.Popen()

class subprocess.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)

各參數含義如下:

args:

args參數。可以是一個字符串,可以是一個包含程序參數的列表。要執行的程序一般就是這個列表的第一項,或者是字符串本身。

subprocess.Popen([ "cat" , "test.txt" ],shell=False)
subprocess.Popen( "cat test.txt", shell=True )

這個命令實際上

subprocess.Popen( "cat test.txt" , shell = True )

相當於

subprocess.Popen([ "/bin/sh" , "-c" , "cat test.txt" ])

在*nix下,當shell=False(默認)時,Popen使用os.execvp()來執行子程序。args一般要是一個[列表]。如果args是個字符串的話,要設置shell=True

 

 

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)
實際上,上面的幾個函數都是基於Popen()的封裝(wrapper)。這些封裝的目的在於讓我們容易使用子進程。當我們想要更個性化我們的需求的時候,就要轉向Popen類,該類生成的對象用來代表子進程。

與上面的封裝不同,Popen對象創建后,主程序不會自動等待子進程完成。我們必須調用對象的wait()方法,父進程才會等待 (也就是阻塞block),舉例:

>>> import subprocess
>>> child = subprocess.Popen(['ping','-c','4','blog.linuxeye.com'])
>>> print 'parent process'

從運行結果中看到,父進程在開啟子進程之后並等待child的完成后,再運行print。
此外,你還可以在父進程中對子進程進行其它操作,比如我們上面例子中的child對象:


child.poll() # 檢查子進程狀態
child.kill() # 終止子進程
child.send_signal() # 向子進程發送信號
child.terminate() # 終止子進程
子進程的PID存儲在child.pid

子進程的文本流控制

子進程的標准輸入、標准輸出和標准錯誤如下屬性分別表示:

child.stdin
child.stdout
child.stderr
可以在Popen()建立子進程的時候改變標准輸入、標准輸出和標准錯誤,並可以利用subprocess.PIPE將多個子進程的輸入和輸出連接在一起,構成管道(pipe),如下2個例子:

>>> import subprocess
>>> child1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE)
>>> print child1.stdout.read(),
#或者child1.communicate()
>>> 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()

subprocess.PIPE實際上為文本流提供一個緩存區。child1的stdout將文本輸出到緩存區,隨后child2的stdin從該PIPE中將文本讀取走。child2的輸出文本也被存放在PIPE中,直到communicate()方法從PIPE中讀取出PIPE中的文本。
注意:communicate()是Popen對象的一個方法,該方法會阻塞父進程,直到子進程完成

 

7、call、check_call、check_output的區別

根據上面的結果,我們可知:

  • ret1 = subprocess.call(cmd):ret1是cmd命令執行后的狀態碼,cmd執行的結果會在終端顯示出來,也就是說如果不需要判斷命令的執行結果的狀態碼,直接subprocess.call(cmd)即可,不需要用一個變量去接收狀態碼。
  • ret2 = subprocess.check_call(cmd):跟call一樣的,只是如果狀態碼不是0,即命令執行失敗的時候會拋出異常。
  • ret3 = subprocess.check_output(cmd): call和check_call的ret是cmd命令的狀態碼,cmd的執行結果是在終端顯示的,而check_output的cmd執行結果不會顯示在終端,而是保存在ret中。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM