在写python脚本的时候,经常需要调用系统命令,常用的python调用系统命令的方法主要有subprocess.call和os.popen。默认情况下subprocess.call的方法结果是返回值,即1或0,而os.popen则是命令运行的结果,可以用readlines(读取所有行,返回数组)或者read(读读取所有行,返回str)来读取。

subprocess类总主要的方法有:

subprocess.call:开启子进程,开启子进程,运行命令,默认结果是返回值,不能try  

subprocess.check_call:运行命令,默认结果是返回值,可以try  

subprocess.check_out(2.7中才有这个方法) 开启子进程,运行命令,可以获取命令结果,可以try  
subprocess.Popen 开启子进程,运行命令,没有返回值,不能try,可以获取命令结果

subprocess.PIPE 初始化stdin,stdout,stderr,表示与子进程通信的标准流
Popen.poll 检查子进程是否结束,并返回returncode
Popen.wait等待子进程是否结束,并返回retrurncode

比如check_call的sample:

1
2
3
4
5
6
7
8
9
10
import  subprocess
import  traceback
cmd = 'hadoop fs -ls hdfs://xxxxx'
try :
     e = subprocess.check_call(cmd,shell = True ,stdout = subprocess.PIPE)
     print  "return code is: %s" % ( str (e))
     #print stdout.read()
except  Exception,re:
     print  "message is:%s"  % ( str (re))
     traceback.print_exc()

分析subprocess的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class  CalledProcessError(Exception):    #首先定义了一个exception,用来在check_call和 check_output中raise exception
     def  __init__( self , returncode, cmd, output = None ):
         self .returncode  =  returncode
         self .cmd  =  cmd
         self .output  =  output
     def  __str__( self ):
         return  "Command '%s' returned non-zero exit status %d"  %  ( self .cmd,  self .returncode)
..........
def  call( * popenargs,  * * kwargs): 
     return  Popen( * popenargs,  * * kwargs).wait()   #call方法调用wait
def  check_call( * popenargs,  * * kwargs):
     retcode  =  call( * popenargs,  * * kwargs)   #调用call,返回返回值
     if  retcode:
         cmd  =  kwargs.get( "args" )
         if  cmd  is  None :
             cmd  =  popenargs[ 0 ]
         raise  CalledProcessError(retcode, cmd)   #可以抛出异常
     return  0
def  check_output( * popenargs,  * * kwargs):
     if  'stdout'  in  kwargs:
         raise  ValueError( 'stdout argument not allowed, it will be overridden.' )
     process  =  Popen(stdout = PIPE,  * popenargs,  * * kwargs)
     output, unused_err  =  process.communicate()   #获取标准输出和标准错误输出
     retcode  =  process.poll()    #检查子进程是否结束,并返回returncode
     if  retcode:
         cmd  =  kwargs.get( "args" )
         if  cmd  is  None :
             cmd  =  popenargs[ 0 ]
         raise  CalledProcessError(retcode, cmd, output = output)
     return  output
有时候我们需要在运行命令时可以获取返回值,获取结果,并且能够try。

可以对上面的代码进行组合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# -*- coding: utf8 -*-
import  exceptions
import  subprocess
import  traceback
class  CalledCommandError(Exception):
     def  __init__( self , returncode, cmd, errorlog,output):
         self .returncode  =  returncode
         self .cmd  =  cmd
         self .output  =  output
         self .errorlog  =  errorlog
     def  __str__( self ):
         return  "命令运行错误:'%s',返回值: %s,错误信息: %s"  %  ( self .cmd,  str ( self .returncode) , self .errorlog)
def  run_command_all( * popenargs,  * * kwargs):
     allresult  =  {}
     cmd  =  popenargs[ 0 ]
     if  'stdout'  in  kwargs  or  'stderr'  in  kwargs :
         raise  ValueError( '标准输出和标准错误输出已经定义,不需设置。' )
     process  =  subprocess.Popen(stdout = subprocess.PIPE,shell = True ,stderr  =  subprocess.PIPE, * popenargs,  * * kwargs)
     output, unused_err  =  process.communicate()
     retcode  =  process.poll()
     if  retcode:
         #print retcode,cmd,unused_err,output
         raise  CalledCommandError(cmd,retcode,errorlog = unused_err,output = output)
     allresult[ 'cmd' =  cmd
     allresult[ 'returncode' =  retcode
     allresult[ 'errorlog' =  unused_err
     allresult[ 'outdata' =  output
     return  allresult
if  __name__  = =  '__main__' :
     cmd  =  'hadoop fs -ls xxxx|wc -l'
     try :
         e = run_command_all(cmd)
         print  "ok"
     except  Exception,re:
         print  ( str (re))
         print  "failed"
         traceback.print_exc()