【摸鱼笔记】subprocess,用子进程访问外部命令

subprocess是一个非常强大的模块,它能通过启动新进程的方式执行外部命令、访问系统Shell、管道等。

同时也能捕获这些新进程的输出和错误信息;

subprocess模块是Python的标准库中的一部分,支持 Python 3.5 及 3.5 以上版本;

3.5 以下版本需要额外安装;

执行外部命令

subprocess.run()

subprocess.run() 用于运行外部命令并等待其完成;

capture_output: 抓取输出;capture_output 参数 与 stdout,stderr 相关,

在不传入capture_output 和 stdout、stderr 的默认情况下,subprocess不会抓取 stdout 和 stderr,并且返回值对象里这两个属性为
None。

传入stdout=PIPE 和 stderr=PIPE 或者 stdout=PIPE、stderr=PIPE 其中一个,subprocess会对应着抓取它们;

如果希望抓取并将两个流合并在一起,可以使用 stdout=PIPE 和 stderr=STDOUT;

直接传入 capture_output=True,subprocess会stdout、stderr两个都抓取;

因为在capture_output=True时,内置的 Popen 对象将自动用 stdout=PIPE 和 stderr=PIPE 创建管道。

所以stdout 和 stderr 参数不应当与 capture_output 同时传入。

check: 返回状态检查;check 参数和子进程运行退出状态码有关

当子进程退出时 return code(状态码) 不为 0,则会触发 CalledProcessError异常;

退出的 return code 会保存到 CalledProcessError.returncode 属性中,

如果 stdout、stderr有被抓取,则 stdout 和 stderr 也会在 CalledProcessError.stdout 和 CalledProcessError.stderr属性里;

timeout :超时时间,如果传入 timeout,并且进程花费的时间超出 timeout,则会触发TimeoutExpired异常;

text: 功能类似 universal_newlines 参数,

默认不传入的情况下,subprocess.run() 返回的stdout、stderr是字节类型,

当text或者universal_newlines为True,stdout、stderr输出是字符串类型;

cwd: 指定 subprocess 子进程工作路径;

input :向子进程传入的参数,可选参数,以下是官方文档的解释

input 参数将被传递给 Popen.communicate() 以及子进程的 stdin。它必须是一个字节序列;

如果指定了 encoding 或 errors 或者将 text 设置为 True,那么也可以是一个字符串。

当使用此参数时,在创建内部 Popen 对象时将自动带上 stdin=PIPE,并且不能再手动指定 stdin 参数。

一般使用

import subprocess

complete = subprocess.run(["ipconfig", "/all"],
                          capture_output=True,
                          text=True)
print(complete.stdout)

拼接参数

如果命令需要接受参数,可以将它们作为列表的一部分传递给subprocess.run()或subprocess.Popen()。

例如,要将文件名作为参数传递给命令,可以这样做:

import subprocess

sub_path = "data_lake"
complete = subprocess.run(["dir", sub_path],
                          shell=True,
                          capture_output=True,
                          text=True,
                          cwd="E:\\VsCodeProjects\\")
print(complete.stdout)

指定路径

使用cwd参数来指定执行外部命令的工作目录。例如,要在特定目录中执行命令,可以这样做:

import subprocess

complete = subprocess.run(["dir"],
                          shell=True,
                          capture_output=True,
                          text=True,
                          cwd="E:\\VsCodeProjects\\")
print(complete.stdout)

使用Shell命令

默认情况下,subprocess不会使用Shell来执行命令。这是出于安全考虑,以防止潜在的Shell注入攻击。但有些情况下,可能需要使用Shell来执行命令,可以将shell参数设置为True。

import subprocess

complete = subprocess.run(["dir", "nonexistent"],
                          shell=True,
                          capture_output=True,
                          text=True)
print("标准输出:")
print(complete.stdout)
print("标准错误:")
print(complete.stderr)

输入输出

标准输出

import subprocess

# 使用 capture_output
complete = subprocess.run(["ipconfig", "/all"],
                          capture_output=True,
                          text=True)
print(complete.stdout)

# 单独使用 stdout
complete = subprocess.run(["ipconfig", "/all"],
                          stdout=subprocess.PIPE,
                          text=True)
print(complete.stdout)

# 单独使用 stdout 输出到txt
with open("stdout_tmp.txt", mode="w", encoding="utf8") as fw:
    complete = subprocess.run(["ipconfig", "/all"],
                              stdout=fw,
                              text=True)
    print(complete.stdout)

# stdout 与 stderr 合并
complete = subprocess.run(["ipconfig", "/all"],
                          stdout=subprocess.PIPE,
                          stderr=subprocess.STDOUT,
                          text=True)
print(complete.stdout)

标准输入

subprocess模块还可以将数据传递给外部命令的标准输入。要实现这一点,可以使用stdin参数,并将其设置为一个文件对象或一个字节串。

import subprocess

input_data = "Hello, subprocess!"
complete = subprocess.run(["findstr", "subprocess"],
                          input=input_data,
                          capture_output=True,
                          text=True)
print(complete.stdout)

标准错误

与标准输出类似,subprocess还可以捕获标准错误信息。要捕获标准错误,请使用stderr参数。

import subprocess

complete = subprocess.run(["dir", "nonexistent"],
                          shell=True,
                          capture_output=True,
                          text=True)
print("标准输出:")
print(complete.stdout)
print("标准错误:")
print(complete.stderr)

子进程运行状态检查

执行外部命令时,通常需要处理错误。以下是一些处理错误的常用方法

抓取stderr内容

import subprocess

complete = subprocess.run(["dir", "nonexistent"],
                          shell=True,
                          capture_output=True,
                          text=True)
if complete.returncode != 0:
    print("stderr:", complete.stderr)

触发 CalledProcessError

import subprocess

try:
    complete = subprocess.run(["dir", "nonexistent"],
                              shell=True,
                              check=True,
                              capture_output=True,
                              text=True)
    print("stdout:", complete.stdout)
except subprocess.CalledProcessError as e:

    print("CalledProcessError:")
    print("CalledProcessError.returncode:", e.returncode)
    print("CalledProcessError.stdout:", e.stdout)
    print("CalledProcessError.stderr:", e.stderr)

超时处理

subprocess还允许您设置执行命令的超时时间,以防止命令运行时间过长。要实现这一点,您可以使用timeout参数。

import subprocess

try:
    complete = subprocess.run(["pause"],
                              shell=True,
                              timeout=12,
                              capture_output=True,
                              text=True)
    print(complete.stdout)
except subprocess.TimeoutExpired as e:
    print("TimeoutExpired")
    print("TimeoutExpired.stdout", e.stdout)
    print("TimeoutExpired.stderr", e.stderr)

subprocess.Popen()

subprocess.Popen()提供了更多的灵活性,允许与进程进行交互,而不仅仅是等待它完成。

args 应当是一个程序参数的序列或者是一个单独的字符串或 path-like object。

默认情况下,如果 args 是序列则要运行的程序为 args 中的第一项。

stdin, stdout 和 stderr 分别指定被执行程序的标准输入、标准输出和标准错误文件句柄;

可以传入的值有 None, PIPE, DEVNULL, 或者文件对象;

当使用默认设置 None 时,将不会进行任何重定向;

PIPE 表示应当新建一个连接子进程的管道;

DEVNULL 表示将使用特殊文件 os.devnull;

stderr 还可以为 STDOUT,stdout 和 stderr 合并;

shell:默认为 False, 指定是否使用 shell 执行程序;

如果 cwd 不为 None,此函数在执行子进程前会将当前工作目录改为 cwd,cwd 可以是一个字符串、字节串或 路径类对象。

text: 功能类似 universal_newlines 参数,

默认不传入的情况下,subprocess.Popen() 返回的stdout、stderr是字节类型,

当text或者universal_newlines为True,stdout、stderr输出是字符串类型;

encoding,errors: 在默认情况下,文件对象将以二进制模式打开。

如果指定了 encoding 或 errors,或者如果 text 为真值,

则文件对象 stdin, stdout 和 stderr 将使用指定的 encoding 和 errors 以文本模式打开。

import subprocess

# 执行命令
process = subprocess.Popen(["ls", "-l"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

# 读取标准输出和错误
out, err = process.communicate()

print("标准输出:")
print(out)

print("标准错误:")
print(err)

管道和重定向

subprocess还可以创建管道,将一个命令的输出连接到另一个命令的输入。这在处理复杂的数据处理任务时非常有用。

例如,要将一个命令的输出传递给另一个命令,

import subprocess

# 创建第一个命令的进程
subprocess1 = subprocess.Popen(["dir", "E:\\PyCharmProjects\\nicole\\"],
                               shell=True,
                               stdout=subprocess.PIPE,
                               text=True)

# 创建第二个命令的进程,将第一个命令的输出连接到它的输入
subprocess2 = subprocess.Popen(["findstr", "favicon"],
                               shell=True,
                               stdin=subprocess1.stdout,
                               stdout=subprocess.PIPE,
                               text=True)

# 从第二个命令的标准输出中读取结果
complete = subprocess2.communicate()[0]
print(complete)

子进程通信

subprocess模块同时读取和写入标准输入和输出。这对于与外部进程进行双向通信非常有用。

以下是一个示例,演示如何使用subprocess进行双向通信:

import subprocess

# 创建命令进程
process = subprocess.Popen(["python", "-u"],
                           stdin=subprocess.PIPE,
                           stdout=subprocess.PIPE,
                           stderr=subprocess.PIPE,
                           text=True)

# 写入数据到标准输入
with process.stdin as std_in:
    std_in.write("print('Hello from child process')\n")

# 读取并打印标准输出
output, errors = process.communicate()
print("输出:", output, errors)
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

The_Singing_Towers

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值