python之执行shell命令的几种方法

发布时间 2023-03-30 23:15:32作者: sureZ_ok

这里介绍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类来实现我们需要的复杂功能。

参考:

  1. Python执行shell命令(并获取执行结果)
  2. [python]调用外部exe 阻塞式和非阻塞式的几种方法
  3. python之subprocess模块详解
  4. python:subprocess模块