当前位置:  首页>> 技术小册>> Python编程轻松进阶(一)

2.3.7 在Python程序中运行命令

在Python编程中,经常需要执行外部命令或程序以完成特定任务,比如文件操作、系统监控、自动化测试等。Python提供了几种方式来实现这一需求,包括使用标准库中的subprocess模块、os模块中的部分函数,以及更高级的第三方库如shpexpect等。本章节将重点介绍如何使用subprocess模块在Python程序中运行命令,因为它提供了最灵活和强大的方式来处理外部命令的执行。

2.3.7.1 subprocess模块简介

subprocess模块允许你启动新的进程,连接到它们的输入/输出/错误管道,并获取它们的返回码。这是Python执行外部命令的推荐方式,因为它比使用os.system()os.popen()等旧方法更加安全和灵活。

subprocess模块中的几个常用函数包括:

  • subprocess.run()(Python 3.5+):推荐用于新的代码,它是一个高级接口,用于执行命令并等待完成。
  • subprocess.Popen():一个更底层的接口,提供了更多的灵活性,比如可以非阻塞地执行命令。
  • subprocess.call()subprocess.check_call()subprocess.check_output():这些函数是subprocess.run()的前身,虽然在新代码中推荐使用subprocess.run(),但在一些旧代码中仍然可以看到它们的身影。

2.3.7.2 使用subprocess.run()执行命令

subprocess.run()函数是Python 3.5及以后版本中引入的,用于替代subprocess.call()subprocess.check_call()subprocess.check_output()。它提供了一个简洁的接口来执行外部命令并获取其输出。

基本用法

  1. import subprocess
  2. # 执行命令并等待完成
  3. result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
  4. # 检查命令是否成功执行
  5. if result.returncode == 0:
  6. print("命令执行成功,输出如下:")
  7. print(result.stdout)
  8. else:
  9. print("命令执行失败,错误信息如下:")
  10. print(result.stderr)

在这个例子中,subprocess.run()执行了ls -l命令(在Unix/Linux系统中列出当前目录下的文件和文件夹的详细信息),capture_output=True参数用于捕获命令的标准输出和标准错误输出,text=True参数(在Python 3.7+中引入)确保输出以文本形式返回,而不是字节串。

参数说明

  • args:要执行的命令和参数,应作为列表传递,例如['ls', '-l']
  • capture_output:是否捕获命令的输出,默认为False
  • text:是否在捕获输出时以文本模式打开文件(Python 3.7+),默认为False(即以字节模式打开)。
  • shell:是否通过shell来执行命令(如/bin/sh -c),默认为False。使用shell=True时要小心注入攻击。
  • timeout:命令执行的最大时间(秒),如果命令超时,将抛出subprocess.TimeoutExpired异常。

2.3.7.3 使用subprocess.Popen()执行命令

如果你需要更复杂的控制,比如同时执行多个命令、非阻塞地执行命令或处理大量的输入输出数据,那么subprocess.Popen()可能是更好的选择。

基本用法

  1. import subprocess
  2. # 创建Popen对象
  3. proc = subprocess.Popen(['grep', 'python'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
  4. # 向命令发送输入数据
  5. stdout, stderr = proc.communicate(input='Python is awesome!\nPython is fun!\n')
  6. # 检查命令是否成功执行
  7. if proc.returncode == 0:
  8. print("命令执行成功,输出如下:")
  9. print(stdout)
  10. else:
  11. print("命令执行失败,错误信息如下:")
  12. print(stderr)

在这个例子中,subprocess.Popen()被用来执行grep命令,它搜索输入中包含“python”的行。stdinstdoutstderr参数分别用于指定子进程的标准输入、标准输出和标准错误输出的处理方式。communicate()方法用于向子进程发送数据并等待其完成,同时获取输出和错误信息。

注意

  • 使用Popen时,应始终调用communicate()方法来发送数据和获取输出,这样可以避免死锁等问题。
  • 如果不需要与子进程进行交互(即不需要发送数据或读取输出),则可以将stdinstdoutstderr设置为Nonesubprocess.DEVNULL(Python 3.3+)。

2.3.7.4 注意事项

  • 安全:当使用shell=True或构造包含外部输入的命令时,要特别小心注入攻击。尽量使用列表形式传递命令和参数,避免使用字符串拼接。
  • 错误处理:检查命令的返回码以确定是否成功执行,并妥善处理标准输出和标准错误输出。
  • 跨平台兼容性:在编写跨平台的Python脚本时,要注意不同操作系统中命令的差异。

2.3.7.5 小结

通过subprocess模块,Python程序能够灵活且安全地执行外部命令。subprocess.run()subprocess.Popen()是执行外部命令的两种主要方式,它们各自适用于不同的场景。掌握这些技能将极大地增强你的Python脚本编写能力,使其能够完成更加复杂和自动化的任务。在编写涉及外部命令的Python脚本时,请务必注意安全性、错误处理和跨平台兼容性。