在写python代码的时候,有时会需要调用系统命令执行。这里总结下调用系统命令的方法及各自的特点。

一、os模块函数执行

1、os.system

先看示例:

1>>> import os
2>>> os.system('ls')
3bin  etc  games  include  java  jdk  lib  man  sbin  scripts  share  src
40

注意这里最后会返回一个returncode 零,感觉挺蛋疼的,在utuntu和centos上都会有。另外要注意这里是在交互模式下执行的有输出,如果写在py文件里执行,没有标准输出。

特点: 仅仅在一个子终端运行系统命令,而不能获取命令执行后的返回信息。如果想获取返回的结果,需要结合print 操作,执行流程如下:

1system(command) -> exit_status
2Execute the command (a string) in a subshell.

2、os.popen

也是os模块下的一个函数,示例如下:

1>>> import os
2>>> os.popen('ls')
3>>> os.popen('ls').readlines()
4['binn', 'etcn', 'gamesn', 'includen', 'javan', 'jdkn', 'libn', 'mann', 'sbinn', 'scriptsn', 'sharen', 'srcn']

特点: 该方法不但执行命令还返回执行后的信息对象,好处在于将返回的结果赋于一变量,便于程序的处理。其执行流程如下:

1popen(command [, mode='r' [, bufsize]]) -> pipe
2Open a pipe to/from a command returning a file object.

需要注意的是,使用os.popen执行命令的参数或者返回中包含了中文文字就会报错(该情况下强烈建议使用subprocess模块),报错信息如下:

1Traceback (most recent call last):
2  File "./361waytest.py", line 13, in sendFax
3    os.popen(cmd)
4UnicodeEncodeError: 'ascii' codec can't encode characters in position 46-52: ordinal not inrange(128)

二、subprocess模块函数执行

subprocess模块主要用于替代以下几个模块函数(具体可以参看 官方docs 文档页面

os.system
os.spawn*
os.popen*
popen2.*
commands.*

相对应的subprocess 模块里有 call 函数和 popen 函数 。

1、subprocess.call

call 函数的用法如下:

1subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)

可以看出,相对于os模块中的函数,这里可以指定的选项更多。

 1>>> import subprocess
 2>>> subprocess.call(["ls", "-l"])
 3total 40
 4drwxr-xr-x 2 root root 4096 Oct 25  2013 bin
 5drwxr-xr-x 2 root root 4096 Jan 24  2013 etc
 6drwxr-xr-x 2 root root 4096 Jan 24  2013 games
 7drwxr-xr-x 2 root root 4096 Jan 24  2013 include
 8lrwxrwxrwx 1 root root    3 Jul  4  2013 java -> jdk
 9drwxr-xr-x 8 root root 4096 Sep 28  2013 jdk
10drwxr-xr-x 3 root root 4096 Jan 24  2013 lib
11lrwxrwxrwx 1 root root    9 Jan 24  2013 man -> share/man
12drwxr-xr-x 2 root root 4096 May 29 04:01 sbin
13drwxr-xr-x 2 root root 4096 May 29 08:19 scripts
14drwxr-xr-x 7 root root 4096 Sep 28  2013 share
15drwxr-xr-x 2 root root 4096 Jan 24  2013 src
160

交互式模式下,call 也会有returncode 0 输出,不过在py文件里执行时,ruturn的结果并不会将最后的 0 输出。不过在使用call 函数时,需要注意后面的几个参数

Warning:
开启shell=True是危险的(或不安全的)
Using shell=True can be a security hazard. See the warning under Frequently Used Arguments for details.

Note:
尽量不要启用标准输出和标准错误输出需要管道,call有可能会导致子进程死锁。如需管道时,请使用Popen函数
Do not use stdout=PIPE or stderr=PIPE with this function as that can deadlock based on the child process output volume. Use Popen with the communicate() method when you need pipes.

subprocess.call 主要用于替换 os.system ,具体如下:

1status = os.system("mycmd" + " myarg")
2# becomes
3status = subprocess.call("mycmd" + " myarg", shell=True)

2、Popen类函数

sub.process.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)

可以看出其支持的参数相当多,下面结合示例看下其用法:

 1>>> subprocess.Popen('ls')
 2>>> bin  etc  games  include  java      jdk  lib  man  sbin  scripts  share  src
 3加参数时
 4>>> subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
 5>>> p = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
 6>>> for line in p.stdout.readlines():
 7...     print line
 8...
 9bin
10etc
11games
12include
13java
14jdk
15lib
16man
17sbin
18scripts
19share
20src

subprocess.Popen用于替代 os.popen、os.popen2、os.popen3、os.popen4 ,这里只列举下替代os.open 的用法

1pipe = os.popen("cmd", 'r', bufsize)
2==>
3pipe = Popen("cmd", shell=True, bufsize=bufsize, stdout=PIPE).stdout
4pipe = os.popen("cmd", 'w', bufsize)
5==>
6pipe = Popen("cmd", shell=True, bufsize=bufsize, stdin=PIPE).stdin

其他代替部分可以查看官方文档。

subprocess.call 和 subprocess.Popen 使用上也有区别,由于不是本篇幅的重点,这里不再赘述。

三、使用commands模块

由于commands也在subprocess模块替代的范畴,这里就不再说commands模块的用法,直接上示例:

1>>> import commands
2>>> dir(commands)
3['__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'getoutput', 'getstatus', 'getstatusoutput', 'mk2arg', 'mkarg']
4>>> commands.getoutput("ls")
5'binnetcngamesnincludenjavanjdknlibnmannsbinnscriptsnsharensrc'
6>>> commands.getstatusoutput("ls")
7(0, 'binnetcngamesnincludenjavanjdknlibnmannsbinnscriptsnsharensrc')