什么是Python中的子进程?【5个使用示例】

子进程使您能够与操作系统进行全新层次的交互。

我们的计算机一直在运行子进程。实际上,仅通过阅读本文,您就会运行许多进程,例如网络管理器或互联网浏览器本身。

有趣的是,我们在计算机上执行的任何操作都涉及调用子进程。即使我们只是在 python 编写一个简单的“hello world”脚本,这个观点仍然是正确的。

子进程的概念可能看起来很模糊,即使您已经学习编程一段时间。本文将深入介绍子进程的主要概念以及如何使用Python subprocess standard library

完成本教程后,您将能够:

  • 了解子进程的概念
  • 掌握Python子进程库的基础知识
  • 通过有用的示例练习Python技能

让我们开始吧

子进程的概念

广义上说,子进程是由另一个进程创建的 computer process

我们可以将子进程看作是一棵树,其中每个父进程后面都有运行的子进程。我知道这可能相当令人困惑,但让我们通过一个简单的图形来看一下。

有几种方式可以可视化计算机上运行的进程。例如,在UNIX(Linux和MAC)中,我们有 htop,,这是一个交互式进程查看器。

“树模式”是查看运行中子进程的最有用工具。我们可以使用 F5 来激活它。

如果我们仔细看命令部分,就可以注意到运行在我们计算机上的进程的结构。


一切都始于命令 /sbin/init,它是在我们计算机上启动每个进程的命令。从那一点开始,我们可以看到其他进程的开始,比如 xfce4-screenshoterxfce4-terminal(这导致了更多的子进程)

看看Windows,我们有传说中的 task manager,当我们需要终止那些在机器上崩溃的程序时非常有用。

现在我们有了一个清晰明确的概念。让我们看看如何在Python中实现子进程。

Python中的子进程

在Python中,子进程是一个Python脚本委托给操作系统(OS)的任务。

子进程库允许我们直接从Python执行和管理子进程。这涉及使用标准输入 stdin,标准输出 stdout 和返回代码。

我们无需使用PIP安装它,因为它是Python standard library.的一部分。

因此,我们只需导入模块即可在Python中使用子进程。

import subprocess

# 使用模块 ....

注意:要按照本文进行操作,您应该使用Python 3.5 +。

要查看您当前的Python版本,只需运行。

❯ python --version
Python 3.9.5 # 我的结果

如果您得到的Python版本是2.x,则可以使用以下命令

python3 --version

继续讨论,子进程库背后的主要思想是能够通过从Python解释器直接执行任何命令与操作系统进行交互。

这意味着我们可以做任何我们想做的事情,只要我们的操作系统允许我们(并且只要您不删除您的根文件系统 😅)。

让我们通过创建一个简单的脚本来查看如何使用它,该脚本列出当前目录的文件。

第一个子进程应用

首先,让我们创建一个名为list_dir.py的文件。这将是我们要用来实验列出文件的文件。

touch list_dir.py

现在让我们打开该文件并使用以下代码。

首先,我们导入subprocess模块,然后使用run函数,该函数运行我们作为参数传递的命令。

这个函数在Python 3.5中引入,作为一个友好的快捷方式。subprocess.run函数允许我们运行一个命令并等待其完成,与Popen不同,后者我们可以选择稍后调用communicate。

谈到代码输出,ls是一个命令,它列出当前目录中的文件。因此,如果你运行这个命令,你将得到一个当前目录中文件的列表。

注意:请注意,如果你在Windows上,你需要使用不同的命令。例如,你可以使用“dir”而不是“ls”。

这可能看起来太简单了,你是对的。你想采取一个全面的方法来使用shell带给你的所有功能。所以让我们学习如何使用subprocess传递参数给shell。

例如,要列出隐藏文件(以点开始的文件)以及列出所有文件的元数据,我们可以编写以下代码。

我们将此命令作为字符串运行,并使用参数shell。这意味着我们在执行子进程的开始时调用了一个shell,并且命令参数直接由shell解释。

但是,使用shell=True有很多缺点,最糟糕的是可能存在的安全漏洞。你可以阅读关于这些漏洞的信息。

将命令传递给run函数的最佳方法是使用一个列表,其中lst[0]是要调用的命令(在这种情况下为ls),lst[n]是该命令的参数。

如果我们这样做,我们的代码将如下所示。

如果我们想将子进程的标准输出存储在变量中,我们可以通过将参数capture_output设置为True来实现。

要访问进程的输出,我们使用实例属性stdout。

在这种情况下,我们想将输出存储为字符串,而不是字节,我们可以通过将text参数设置为True来实现。

完美,现在我们了解了subprocess库的基本知识,是时候进入一些使用示例了。

Python中subprocess的使用示例

在本节中,我们将回顾subprocess库的一些实际用途。您可以在这个Github repository中查看它们的全部用途。

程序检查器

这个库的主要用途之一是能够进行简单的操作系统操作。

例如,一个简单的脚本可以检查程序是否已安装。在Linux中,我们可以使用which命令来实现这一点。

'''带有subprocess的程序检查器'''

import subprocess

program = 'git'

process = subprocess.run(['which', program], capture_output=True, text=True)

if process.returncode == 0: 
    print(f'程序"{program}"已安装')

    print(f'二进制文件的位置为:{process.stdout}')
else:
    print(f'对不起,{program}未安装')

    print(process.stderr)

注意:在UNIX中,当一个命令成功执行时,它的状态码是0。否则,在执行过程中出了些问题

由于我们没有使用shell=True参数,我们可以安全地获取用户输入。此外,我们还可以使用正则表达式模式检查输入是否为有效程序。

import subprocess

import re

programs = input('用空格分隔程序:').split()

secure_pattern = '[wd]'

for program in programs:

    if not re.match(secure_pattern, program):
        print("对不起,我们无法检查该程序")

        continue

    process = subprocess.run(
        ['which', program], capture_output=True, text=True)

    if process.returncode == 0:
        print(f'程序"{program}"已安装')

        print(f'二进制文件的位置为:{process.stdout}')
    else:
        print(f'对不起,{program}未安装')

        print(process.stderr)

    print('n')

在这种情况下,我们从用户那里获取程序,并使用正则表达式表达式验证程序字符串只包含字母和数字。我们用for循环检查每个程序的存在。

注意:查看这个online regex tester

Python中的简单Grep

你的朋友Tom在一个文本文件中有一系列的模式,还有另一个大文件,他想要得到每个模式的匹配数。他会花几个小时来运行每个模式的 grep command

幸运的是,你知道如何用Python解决这个问题,并帮助他在几秒钟内完成这个任务。

import subprocess

patterns_file = 'patterns.txt'
readfile = 'romeo-full.txt'

with open(patterns_file, 'r') as f:
    for pattern in f:
        pattern = pattern.strip()

        process = subprocess.run(
            ['grep', '-c', f'{pattern}', readfile], capture_output=True, text=True)

        if int(process.stdout) == 0:
            print(
                f'模式"{pattern}"没有匹配到{readfile}中的任何行')

            continue

        print(f'模式"{pattern}"匹配了{process.stdout.strip()}次')

查看这个文件,我们定义了两个变量,这些变量是我们想要处理的文件名。然后我们打开包含所有模式的文件并对其进行迭代。接下来,我们调用一个子进程来运行带有“-c”标志(表示计数)的grep命令,并根据条件确定匹配的输出。

如果您运行此文件(请记住您可以从这个Github repo下载文本文件)

使用subprocess设置虚拟环境

你可以用Python做的最酷的事情之一是自动化处理。这种类型的脚本可以每周为您节省几个小时的时间。

例如,我们将创建一个设置脚本,该脚本将为我们创建一个虚拟环境,并尝试在当前目录中找到一个requirements.txt文件以安装所有依赖项。

“`python
import subprocess

subprocess.run([‘open', ‘https://www.example.com'])
subprocess.run([‘xdg-open', ‘https://www.example.com'])
“`

通过使用subprocess模块的run()函数,我们可以在Python脚本中打开外部程序。上面的代码示例展示了如何在Python中打开一个URL链接。在macOS系统中,可以使用open命令打开指定的链接;在Linux系统中,可以使用xdg-open命令。

我们通过调用子进程的二进制位置可以运行其他程序。
让我们尝试打开我的首选网络浏览器brave

import subprocess

subprocess.run('brave')

这将打开一个浏览器实例,如果您已经在运行浏览器,它将打开另一个选项卡。

与其他接受参数的程序一样,我们可以使用参数来产生所需的行为。

import subprocess

subprocess.run(['brave', '--incognito'])

总结

子进程是由另一个进程创建的计算机进程。我们可以使用类似htop和任务管理器的工具来检查计算机正在运行的进程。
Python拥有自己的处理子进程的库。目前,run函数为我们提供了一个简单的接口来创建和管理子进程。
我们可以使用它们创建任何类型的应用程序,因为我们直接与操作系统进行交互。
最后,请记住,学习的最佳方式是通过实践和使用您喜欢的资源。

类似文章