什么是Python中的子进程?【5个使用示例】
子进程使您能够与操作系统进行全新层次的交互。
我们的计算机一直在运行子进程。实际上,仅通过阅读本文,您就会运行许多进程,例如网络管理器或互联网浏览器本身。
有趣的是,我们在计算机上执行的任何操作都涉及调用子进程。即使我们只是在 python 编写一个简单的“hello world”脚本,这个观点仍然是正确的。
子进程的概念可能看起来很模糊,即使您已经学习编程一段时间。本文将深入介绍子进程的主要概念以及如何使用Python subprocess standard library。
完成本教程后,您将能够:
- 了解子进程的概念
- 掌握Python子进程库的基础知识
- 通过有用的示例练习Python技能
让我们开始吧
子进程的概念
广义上说,子进程是由另一个进程创建的 computer process。
我们可以将子进程看作是一棵树,其中每个父进程后面都有运行的子进程。我知道这可能相当令人困惑,但让我们通过一个简单的图形来看一下。
有几种方式可以可视化计算机上运行的进程。例如,在UNIX(Linux和MAC)中,我们有 htop,,这是一个交互式进程查看器。
“树模式”是查看运行中子进程的最有用工具。我们可以使用 F5 来激活它。
如果我们仔细看命令部分,就可以注意到运行在我们计算机上的进程的结构。
一切都始于命令 /sbin/init,它是在我们计算机上启动每个进程的命令。从那一点开始,我们可以看到其他进程的开始,比如 xfce4-screenshoter 和 xfce4-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函数为我们提供了一个简单的接口来创建和管理子进程。
我们可以使用它们创建任何类型的应用程序,因为我们直接与操作系统进行交互。
最后,请记住,学习的最佳方式是通过实践和使用您喜欢的资源。