一、commands模塊
1、介紹
當我們使用Python進行編碼的時候,但是又想運行一些shell命令,去創建文件夾、移動文件等等操作時,我們可以使用一些Python庫去執行shell命令。
commands模塊就是其中的一個可執行shell命令的庫,commands模塊是python的內置模塊,共有三個函數:
- getstatus(file):返回執行
ls -ld file
命令的結果( -ld 代表的是僅列出指定目錄的詳細信息)。 - getoutput(cmd):執行cmd命令,並返回輸出的內容,返回結果為str。
- 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中。