运行shell命令并捕获输出

运行shell命令并捕获输出

技术背景

在Python编程中,经常需要与操作系统的shell进行交互,执行shell命令并获取其输出。Python提供了多种方式来实现这一功能,每种方式适用于不同的Python版本和具体需求。

实现步骤

所有官方维护的Python版本:subprocess.check_output

在所有官方维护的Python版本中,最简单的方法是使用subprocess.check_output函数。该函数运行一个接受参数作为输入的单个程序,并返回打印到stdout的结果。

1
2
3
import subprocess
output = subprocess.check_output(['ls', '-l'])
print(output)

Python 3.5+:subprocess.run

如果使用Python 3.5及以上版本,并且不需要向后兼容,官方文档推荐使用subprocess.run函数。它为subprocess模块提供了一个非常通用的高级API。

1
2
3
4
import subprocess
result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
output = result.stdout.decode('utf-8')
print(output)

Python 3 - 3.4:更多关于check_output

如果使用较旧版本的Python,或者需要适度的向后兼容性,可以使用check_output函数。它从Python 2.7开始就可用。

1
2
3
import subprocess
output = subprocess.check_output(['ls', '-l'])
print(output)

旧版本Python(2.6及以下):subprocess.Popen

如果需要深度的向后兼容性,或者需要比check_outputrun更复杂的功能,则需要直接使用subprocess.Popen对象。

1
2
3
4
import subprocess
p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
print(out.decode('utf-8'))

核心代码

通用函数封装

以下是一个兼容Python 2和3的通用函数,用于执行shell命令并捕获输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from subprocess import check_output, CalledProcessError, STDOUT

def system_call(command):
"""
params:
command: list of strings, ex. `["ls", "-l"]`
returns: output, success
"""
try:
output = check_output(command, stderr=STDOUT).decode()
success = True
except CalledProcessError as e:
output = e.output.decode()
success = False
return output, success

output, success = system_call(["ls", "-l"])
print(output)

最佳实践

  • 安全性:避免直接使用shell=True,因为这可能会带来安全风险。如果需要执行复杂的shell命令,建议分别调用每个进程,并将输出作为输入传递给下一个进程。
  • 错误处理:在执行shell命令时,要注意捕获和处理可能的错误,例如使用try-except块。
  • 输出编码:确保正确处理输出的编码,避免出现乱码问题。

常见问题

  • shell=True的安全问题:直接使用shell=True可能会导致命令注入攻击,建议在安全的环境中使用,或者分别调用每个进程。
  • 死锁问题:在使用Popen对象时,如果不谨慎使用非communicate方法,可能会导致死锁。建议使用communicate方法来处理输入和输出。
  • 编码问题:在处理输出时,要确保使用正确的编码进行解码,避免出现乱码。

运行shell命令并捕获输出
https://119291.xyz/posts/running-shell-command-and-capturing-output/
作者
ww
发布于
2025年6月25日
许可协议