Python中能夠執行shell命令的相關模塊和函數有:python
import commands result = commands.getoutput('cmd') result = commands.getstatus('cmd') result = commands.getstatusoutput('cmd')
隨着Python版本的更新,過多的模塊引發代碼的複雜與冗餘,所以Python新引入了一個模塊subprocess,將以上幾個模塊中的功能集中到它當中,之後咱們只需import這一個便可。shell
subprocess的目的就是啓動一個新的進程而且與之通訊。windows
1. call緩存
父進程等待子進程執行命令,返回子進程執行命令的狀態碼,若是出現錯誤,不進行報錯bash
【這裏說的返回執行命令的狀態碼的意思是:若是咱們經過一個變量 res = subprocess.call(['dir',shell=True]) 獲取的執行結果,咱們能獲取到的是子進程執行命令執行結果的狀態碼,即res=0/1 執行成功或者不成功,並不表明說看不到執行結果,在Python的console界面中咱們是可以看到命令結果的,只是獲取不到。想獲取執行的返回結果,請看check_output。】app
【不進行報錯解釋:若是咱們執行的命令在執行時,操做系統不識別,系統會返回一個錯誤,如:abc命令不存在,這個結果會在console界面中顯示出來,可是咱們的Python解釋器不會提示任何信息,若是想讓Python解釋器也進行報錯,請看check_call】ide
#!/usr/bin/env python # -*- coding:utf-8 -*- import subprocess print "################## subprocess.call ###############" print u"call方法調用系統命令進行執行,若是出錯不報錯" subprocess.call(['dir'],shell=True)
注:shell默認爲False,在Linux下,shell=False時, Popen調用os.execvp()執行args指定的程序;shell=True時,若是args是字符串,Popen直接調用系統的Shell來執行args指定的程序,若是args是一個序列,則args的第一項是定義程序命令字符串,其它項是調用系統Shell時的附加參數。
在Windows下,不論shell的值如何,Popen調用CreateProcess()執行args指定的外部程序。若是args是一個序列,則先用list2cmdline()轉化爲字符串,但須要注意的是,並非MS Windows下全部的程序均可以用list2cmdline來轉化爲命令行字符串。在windows下,調用腳本時要寫上shell=True。
返回結果:函數
###### subprocess.call ####### call方法調用系統命令進行執行,若是出錯不報錯 D:\Program\Python 的目錄 2016/01/27 11:51 1,069 subprocessDemo.py 1 個文件 1,228 字節
2. check_callidea
父進程等待子進程執行命令,返回執行命令的狀態碼,若是出現錯誤,進行報錯【若是returncode不爲0,則舉出錯誤subprocess.CalledProcessError,該對象包含有returncode屬性,可用try…except…來檢查】spa
#!/usr/bin/env python # -*- coding:utf-8 -*- import subprocess print "2. ################## subprocess.check_call ##########" print u"check_call與call命令相同,區別是若是出錯會報錯" subprocess.check_call(['dir'],shell=True) subprocess.check_call(['abc'],shell=True) print u"call方法與check_call方法都知識執行並打印命令到輸出終端,可是獲取不到,若是想獲取到結果使用check_output"
返回結果
2. ################## subprocess.check_call ########## check_call與call命令相同,區別是若是出錯會報錯 驅動器 D 中的卷沒有標籤。 卷的序列號是 C6A1-5AD3 D:\Program\Python 的目錄 2016/01/27 13:05 <DIR> . 2016/01/27 13:05 <DIR> .. 2016/01/27 10:44 <DIR> .idea 2016/01/27 11:23 159 log_analyse.py 2016/01/27 13:05 1,329 subprocessDemo.py 2 個文件 1,488 字節 3 個目錄 26,335,281,152 可用字節 'abc' 不是內部或外部命令,也不是可運行的程序或批處理文件。 這裏是系統執行命令返回的系統報錯 Traceback (most recent call last): 這裏是Python解釋器返回的報錯 File "D:/Program/Python/subprocessDemo.py", line 19, in <module> subprocess.check_call(['abc'],shell=True) File "C:\Python27\lib\subprocess.py", line 540, in check_call raise CalledProcessError(retcode, cmd) subprocess.CalledProcessError: Command '['abc']' returned non-zero exit status 1
3. check_output
父進程等待子進程執行命令,返回子進程向標準輸出發送輸出運行結果,檢查退出信息,若是returncode不爲0,則舉出錯誤subprocess.CalledProcessError,該對象包含有returncode屬性和output屬性,output屬性爲標準輸出的輸出結果,可用try…except…來檢查。
#!/usr/bin/env python # -*- coding:utf-8 -*- import subprocess print "3. ################## subprocess.check_output ##############" res1 = subprocess.call(['dir'],shell=True) res2 = subprocess.check_call(['dir'],shell=True) res3 = subprocess.check_output(['dir'],shell=True) print u"call結果:",res1 print u"check_call結果:",res2 print u"check_output結果:\n",res3
返回結果:
3. ################## subprocess.output ############## 驅動器 D 中的卷沒有標籤。 卷的序列號是 C6A1-5AD3 D:\Program\Python 的目錄 2016/01/27 13:14 <DIR> . 2016/01/27 13:14 <DIR> .. 2016/01/27 10:44 <DIR> .idea 2016/01/27 11:23 159 log_analyse.py 2016/01/27 13:14 1,324 subprocessDemo.py 2 個文件 1,483 字節 3 個目錄 26,334,232,576 可用字節 驅動器 D 中的卷沒有標籤。 卷的序列號是 C6A1-5AD3 D:\Program\Python 的目錄 2016/01/27 13:14 <DIR> . 2016/01/27 13:14 <DIR> .. 2016/01/27 10:44 <DIR> .idea 2016/01/27 11:23 159 log_analyse.py 2016/01/27 13:14 1,324 subprocessDemo.py 2 個文件 1,483 字節 3 個目錄 26,334,232,576 可用字節 call結果: 0 check_call結果: 0 check_output結果: 驅動器 D 中的卷沒有標籤。 卷的序列號是 C6A1-5AD3 D:\Program\Python 的目錄 2016/01/27 13:14 <DIR> . 2016/01/27 13:14 <DIR> .. 2016/01/27 10:44 <DIR> .idea 2016/01/27 11:23 159 log_analyse.py 2016/01/27 13:14 1,324 subprocessDemo.py 2 個文件 1,483 字節 3 個目錄 26,334,232,576 可用字節
可見,call/check_call 返回值均是命令的執行狀態碼,而check_output返回值是命令的執行結果。
若是在執行相關命令時,命令後帶有參數,將程序名(即命令)和所帶的參數一塊兒放在一個列表中傳遞給相關犯法便可,例如:
>>> import subprocess >>> retcode = subprocess.call(["ls", "-l"]) >>> print retcode 0
4. Popen
實際上,subprocess模塊中只定義了一個類: Popen。上面的幾個函數都是基於Popen()的封裝(wrapper)。從Python2.4開始使用Popen來建立進程,用於鏈接到子進程的標準輸入/輸出/錯誤中去,還能夠獲得子進程的返回值。這些封裝的目的在於讓咱們容易使用子進程。當咱們想要更個性化咱們的需求的時候,就要轉向Popen類,該類生成的對象用來表明子進程。
構造函數以下:
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)
與上面的封裝不一樣,Popen對象建立後,主程序不會自動等待子進程完成。咱們必須調用對象的wait()方法,父進程纔會等待 (也就是阻塞block)。
a) 不等待的子進程
#!/usr/bin/env python import subprocess child = subprocess.Popen(['ping','-c','4','www.baidu.com']) print 'hello'
執行結果:
[root@localhost script]# python sub.py hello [root@localhost script]# PING www.a.shifen.com (61.135.169.125) 56(84) bytes of data. 64 bytes from 61.135.169.125: icmp_seq=1 ttl=55 time=2.04 ms 64 bytes from 61.135.169.125: icmp_seq=2 ttl=55 time=1.58 ms 64 bytes from 61.135.169.125: icmp_seq=3 ttl=55 time=2.22 ms 64 bytes from 61.135.169.125: icmp_seq=4 ttl=55 time=2.13 ms --- www.a.shifen.com ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3008ms rtt min/avg/max/mdev = 1.580/1.995/2.220/0.251 ms
能夠看出,Python並無等到child子進程執行的Popen操做完成就執行了print操做。
b) 添加子進程等待
#!/usr/bin/env python import subprocess child = subprocess.Popen(['ping','-c','4','www.baidu.com']) #建立一個子進程,進程名爲child,執行操做ping -c 4 www.baidu.com child.wait() #子進程等待 print 'hello'
執行結果:
[root@localhost script]# python sub.py PING www.a.shifen.com (61.135.169.125) 56(84) bytes of data. 64 bytes from 61.135.169.125: icmp_seq=1 ttl=55 time=1.82 ms 64 bytes from 61.135.169.125: icmp_seq=2 ttl=55 time=1.65 ms 64 bytes from 61.135.169.125: icmp_seq=3 ttl=55 time=1.99 ms 64 bytes from 61.135.169.125: icmp_seq=4 ttl=55 time=2.08 ms --- www.a.shifen.com ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3009ms rtt min/avg/max/mdev = 1.656/1.889/2.082/0.169 ms hello
看出Python執行print操做是在child子進程操做完成之後才進行的。
此外,你還能夠在父進程中對子進程進行其它操做,好比咱們上面例子中的child對象:
child.poll() # 檢查子進程狀態 child.kill() # 終止子進程 child.send_signal() # 向子進程發送信號 child.terminate() # 終止子進程
ps: 子進程的PID存儲在child.pid
子進程文本流控制
子進程的標準輸入、標準輸出和標準錯誤以下屬性分別表示:
child.stdin | child.stdout | child.stderr
咱們還能夠在Popen()創建子進程的時候改變標準輸入、標準輸出和標準錯誤,並能夠利用subprocess.PIPE將多個子進程的輸入和輸出鏈接在一塊兒,構成管道(pipe),以下2個例子:
例1
#!/usr/bin/env python import subprocess child = subprocess.Popen(['ls','-l'],stdout=subprocess.PIPE) #將標準輸出定向輸出到subprocess.PIPE print child.stdout.read() #使用 child.communicate() 也可
輸出結果:
[root@localhost script]# python sub.py total 12-rw-r--r--. 1 root root 36 Jan 23 07:38 analyse.sh -rw-r--r--. 1 root root 446 Jan 25 19:35 sub.py
例2 #!/usr/bin/env python import subprocess child1 = subprocess.Popen(['cat','/etc/passwd'],stdout=subprocess.PIPE) child2 = subprocess.Popen(['grep','root'],stdin=child1.stdout,stdout=subprocess.PIPE) print child2.communicate()
輸出結果爲
('root:x:0:0:root:/root:/bin/bash\n, None)
subprocess.PIPE實際上爲文本流提供一個緩存區。child1的stdout將文本輸出到緩存區,隨後child2的stdin從該PIPE中將文本讀取走。child2的輸出文本也被存放在PIPE中,直到communicate()方法從PIPE中讀取出PIPE中的文本。
注意:communicate()是Popen對象的一個方法,該方法會阻塞父進程,直到子進程完成
子進程命令解釋
在上面的例子中咱們建立子進程時,所有是調用Python進行解釋,但Python並無將全部命令所有解釋,當Python不能進行解釋時,就緒要調用系統來進行執行。
#!/usr/bin/env python import subprocess subprocess.Popen(['ls','-l']) subprocess.Popen(['ifconfig|grep 127.0.0.1'],shell=True)
結果
>>> subprocess.Popen(['ifconfig|grep 127.0.0.1'],shell=True) <subprocess.Popen object at 0x7f25eb0c1350> >>> inet addr:127.0.0.1 Mask:255.0.0.0