python之执行shell命令的几种方法
这里介绍python执行shell命令的几种方法以及它们之间的区别。
方法1: os.system()方法
函数原型:
# os.system()是阻塞式的
os.system(command)
windows系统下返回值为退出状态码,状态码为0表示执行成功,其它值表示执行不成功;
Linux系统下,返回值是16bit的整数,高8bit表示退出码,低8bit表示结束进程的pid。
例子:
import os
result = os.system('ls .')
print(result)
# 执行结果为:列出当前文件夹文件,返回值result=0表示执行成功
注意事项:
os.system() 在执行system函数执行时会创建一个子进程执行命令,等子进程结束后才会返回到主进程中继续执行(即阻塞式的),同时子进程的执行结果无法影响主进程。
os.system改造为非阻塞形式的方法:
# linux平台加上运算符&,意思是将命令放在后台执行
os.system('python test.py &')
# window平台。可使用DOS的start命令
os.system('start python test.py ')
os.system执行多条命令的方法:
# 如下例子是进入test文件夹,查看其中的文件列表,如下写法是错误的,因为子进程的执行结果无法影响主进程。
os.system("cd test")
os.system("ls .")
# 正确的写法如下,将命令放到同一个进程中执行。
os.system("cd test && ls .")
方法2: os.popen()方法
函数原型:
# os.popen()是非阻塞式的
os.popen(cmd, mode='r', buffering=-1)
# 参数说明:
# Command:调用的命令;
# mode: 模式权限可以是 'r'(默认) 或 'w', 但不能同时读写;
# bufsize 文件需要的缓冲大小 0无缓冲 1行缓冲 其它正值以字节为单位 负值使用系统默认值。
这种调用方式是通过管道的方式来实现,函数返回一个文件对象,可以对这个文件对象进行相关操作。
例子:
import os
f = os.popen('ls .')
lines = f.readlines()
print(lines) # 打印文件内容
f.close() # 关闭文件对象
推荐使用with-as方法,这样不需要显示的写f.close()了
import os
command = 'ls .'
with os.popen(command, "r") as f:
r = f.read()
注意事项:
os.popen()是非阻塞式的,可以通过使用read()或readlines()对返回的文件对象进行阻塞式读,从而产生阻塞式的效果。另外要注意,如果命令执行无法退出或进入交互模式,这种“读”将形成完全阻塞的情况,表现的像程序卡住了。
# p保存command执行后的输出
p = os.popen('ls .').read()
方法3: 使用commands模块
注意:python 3.0 之后移除此命令,使用 subprocess代替
这里还是大概列一下。
函数 | 用途 |
---|---|
commands.getoutput(cmd) | 返回Shell命令的输出内容,忽略返回值 |
commands.getstatusoutput(cmd) | 返回一个元组(status,output),status 代表的 shell 命令的返回状态,如果成功的话是 0;output 是 shell 的返回的结果 |
commands.getstatus(file) | 返回 ls -ld file 执行的结果(返回值很奇怪),该函数已被 Python 丢弃,不建议使用 |
方法4: 使用subprocess模块
subprocess模块功能最为强大,是官方最推荐的做法,可以替代上述方法1-3。
以下的表和文字描述来自于参考3,写得较清晰,我就不必再次整理了。
subprocess模块常用方法:
函数 | 用途 |
---|---|
subprocess.run() | Python 3.5中新增的函数。执行指定的命令,等待命令执行完成后返回一个包含执行结果的CompletedProcess类的实例 |
subprocess.call() | 执行指定的命令,返回命令执行状态,其功能类似于os.system(cmd),同样是阻塞式的 |
subprocess.check_call() | Python 2.5中新增的函数。 执行指定的命令,如果执行成功则返回状态码,否则抛出异常。其功能等价于subprocess.run(..., check=True) |
subprocess.check_output() | Python 2.7中新增的的函数。执行指定的命令,如果执行状态码为0则返回命令执行结果,否则抛出异常。 |
subprocess.getoutput(cmd) | 接收字符串格式的命令,执行命令并返回执行结果,其功能类似于os.popen(cmd).read()和commands.getoutput(cmd) |
subprocess.getstatusoutput(cmd) | 执行cmd命令,返回一个元组(命令执行状态, 命令执行结果输出),其功能类似于commands.getstatusoutput() |
函数细节:
1 subprocess.run()
函数原型:
# 执行args命令,返回值为CompletedProcess类;
# 若未指定stdout,则命令执行后的结果输出到屏幕上,函数返回值CompletedProcess中包含有args和returncode;
# 若指定有stdout,则命令执行后的结果输出到stdout中,函数返回值CompletedProcess中包含有args、returncode和stdout;
# 若执行成功,则returncode为0;若执行失败,则returncode为1;
# 若想获取args命令执行后的输出结果,命令为:output = subprocess.run(args, stdout=subprocess.PIPE).stdout
subprocess.run(args[, stdout, stderr, shell ...])
2 subprocess.call()
函数原型:
# 执行args命令,返回值为命令执行状态码;
# 若未指定stdout,则命令执行后的结果输出到屏幕;
# 若指定stdout,则命令执行后的结果输出到stdout;
# 若执行成功,则函数返回值为0;若执行失败,则函数返回值为1;
#(类似os.system)
subprocess.call(args[, stdout, ...])
3 subprocess.check_call()
函数原型:
# 执行args命令,返回值为命令执行状态码;
# 若未指定stdout,则命令执行后的结果输出到屏幕;
# 若指定stdout,则命令执行后的结果输出到stdout;
# 若执行成功,则函数返回值为0;若执行失败,抛出异常;
#(类似subprocess.run(args, check=True))
subprocess.check_call(args[, stdout, ...])
4 subprocess.check_output()
函数原型:
# 执行args命令,返回值为命令执行的输出结果;
# 若执行成功,则函数返回值为命令输出结果;若执行失败,则抛出异常;
#(类似subprocess.run(args, check=True, stdout=subprocess.PIPE).stdout)
subprocess.check_output(args[, stderr, ...])
其中的入参:
- args:启动进程的参数,默认为字符串序列(列表或元组),也可为字符串(设为字符串时一般需将shell参数赋值为True);
- shell:shell为True,表示args命令通过shell执行,则可访问shell的特性;
- check:check为True时,表示执行命令的进程以非0状态码退出时会抛出;subprocess.CalledProcessError异常;check为False时,状态码为非0退出时不会抛出异常;
- stdout、stdin、stderr:分别表示程序标准标输出、输入、错误信息;run函数返回值为CompletedProcess类,若需获取执行结果,可通过获取返回值的stdout和stderr来捕获; check_output函数若需捕获错误信息,可通过stderr=subprocess.STDOUT来获取;
例子:
见参考4,例子举得比较好,这里不再copy了。
总结
摘抄自参考3:
那么我们到底该用哪个模块、哪个函数来执行命令与系统及系统进行交互呢?总结如下:
- 首先,Python2.4版本引入了subprocess模块用来替换os.system()、os.popen()、os.spawn*()等函数以及commands模块;如果是Python 2.4及以上的版本就应该使用subprocess模块了。
- 如果你的应用使用的Python 2.4以上,但是是Python 3.5以下的版本,Python官方给出的建议是使用subprocess.call()函数。Python 2.5中新增了一个subprocess.check_call()函数,Python 2.7中新增了一个subprocess.check_output()函数,这两个函数也可以按照需求进行使用。
- 如果你的应用使用的是Python 3.5及以上的版本,Python官方给出的建议是尽量使用subprocess.run()函数。
- 当subprocess.call()、subprocess.check_call()、subprocess.check_output()和subprocess.run()这些高级函数无法满足需求时,我们可以使用subprocess.Popen类来实现我们需要的复杂功能。
参考: