目录
前言
1、subprocess.run()
(1)函数参数列表
(2)函数的参数含义
(3)使用示例
2、subprocess.Popen
(1)函数参数列表
(2)函数参数含义
(3)使用示例
3、常见的subprocess.Popen类方法
(1)Popen.poll()
(2)Popen.communicate(input=None, timeout=None)
(3)Popen.send_signal(signal)
(4)Popen.terminate()
(5)Popen.kill()
(6)Popen.stdout
(7)Popen.stderr
(8)Popen.pid
(9)Popen.returncode
4、subprocess.check_call
(1)函数参数列表
(2)参数详解
(3)使用示例
5、subprocess.check_output
(1)函数参数列表
(2)参数详解
(3)使用示例
Python的`subprocess`库主要用于启动新的应用程序或进程,并与它们的输入/输出/错误管道进行交互。
以下是`subprocess`库的一些主要用途:
1. 运行外部命令:你可以使用`subprocess`库运行任何在命令行下可以运行的命令或程序。
2. 交互式进程通信:你可以使用`subprocess`库启动一个新的进程,并通过其标准输入、输出和错误管道与之交互。比如,你可以发送数据给进程的标准输入,或者读取进程的标准输出和错误输出。
3. 管道和重定向:你可以使用`subprocess`库创建管道,将一个进程的输出重定向到另一个进程的输入,或者将进程的输出重定向到一个文件。
4. 进程管理:你可以使用`subprocess`库监控进程的状态,等待进程结束,或者终止进程。
`subprocess`库提供了一套高级API(如`run()`,`check_output()`等函数)和一套低级API(如`Popen`类)。高级API简单易用,适合于简单的用途,如运行一个命令并获取其输出。低级API功能强大,灵活性高,适合于复杂的用途,如交互式进程通信和复杂的管道和重定向。
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, capture_output=False, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None, text=None, env=None, universal_newlines=None, **other_popen_kwargs)
1. `args`:这是要执行的命令和参数,可以是一个字符串或一个参数列表。如果是一个字符串,它会被传递给shell执行;如果是一个参数列表,列表的第一个元素是要执行的命令,后面的元素是命令的参数。
2. `stdin`:这是子进程的标准输入。如果设为`subprocess.PIPE`,你可以通过`input`参数向子进程发送数据;如果设为`subprocess.DEVNULL`,表示关闭子进程的标准输入。
3. `input`:这是发送给子进程的数据。它应该是一个字节串或一个字符串。
4. `stdout`、`stderr`:这两个参数分别表示子进程的标准输出和标准错误。你可以设为`subprocess.PIPE`来捕获子进程的输出/错误,或者设为`subprocess.DEVNULL`来忽略子进程的输出/错误。
5. `capture_output`:如果设为`True`,表示捕获子进程的标准输出和标准错误。
6. `shell`:如果设为`True`,表示在一个shell中执行命令。这在执行需要shell特性(比如管道、文件重定向等)的命令时非常有用。
7. `cwd`:这是子进程的工作目录。默认为None,表示使用当前进程的工作目录。
8. `timeout`:这是子进程的超时时间(以秒为单位)。如果子进程在超时时间内未完成,将引发`TimeoutExpired`异常。
9. `check`:如果设为`True`,表示当子进程返回非零退出状态时,引发`CalledProcessError`异常。
10. `encoding`、`errors`:这两个参数用于编码/解码子进程的输入/输出。默认为None,表示使用系统默认编码。
11. `text`:如果设为`True`,表示以文本模式处理输入/输出(默认为字节模式)。
12. `env`:这是子进程的环境变量。默认为None,表示使用当前进程的环境变量。
13. `universal_newlines`:这个参数在Python 3.7及更高版本中被`text`参数取代。
14. `**other_popen_kwargs`:这是其他传递给`subprocess.Popen()`的关键字参数。
- 运行一个简单的命令:
import subprocess
subprocess.run('ls -l', shell=True)
- 捕获子进程的输出:
result = subprocess.run('ls -l', shell=True, stdout=subprocess.PIPE, text=True)
print(result.stdout)
- 向子进程发送数据:
result = subprocess.run('cat', shell=True, stdout=subprocess.PIPE,
stdin=subprocess.PIPE, input='hello, world!', text=True)
print(result.stdout)
- 处理子进程的非零退出状态:
try:
subprocess.run('false', shell=True, check=True)
except subprocess.CalledProcessError:
print('Command failed')
subprocess.Popen(args, bufsize=- 1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=None, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *, group=None, extra_groups=None, user=None, umask=- 1, encoding=None, errors=None, text=None, pipesize=- 1, process_group=None)
1、`args`:要执行的命令和参数。如果`shell=False`(默认),`args`应该是一个序列,比如`['ls', '-l']`;如果`shell=True`,`args`可以是一个字符串,比如`'ls -l'`。
2、 `bufsize`:指定缓冲策略。0表示不缓冲,1表示行缓冲,其他正数表示使用一个近似大小的缓冲区,负数表示使用系统默认的IO缓冲策略。
3、 `executable`:实际程序路径,一般不需要指定,由`args[0]`确定。
4、 `stdin`, `stdout`, `stderr`:分别表示子进程的标准输入、标准输出和标准错误。可以是任何`file-like`对象,也可以是`subprocess.PIPE`(创建新的管道)、`subprocess.STDOUT`(将错误输出到标准输出流中)或`subprocess.DEVNULL`(忽略输出)。
5、`preexec_fn`:仅在Unix平台上有效,用于指定一个可调用对象,它将在子进程运行之前被调用。
6、`close_fds`:在Unix平台上,如果`close_fds`为`True`,则除了0, 1和2之外的所有文件描述符将在子进程启动之前关闭。在Windows上,如果`close_fds`为`True`,则新创建的子进程将不会继承父进程的输入、输出和错误流。默认为`True`。
7、`shell`:如果`shell=True`,则在一个shell中执行命令。这对于需要执行shell命令的情况非常有用,比如使用管道、通配符等。
8、 `cwd`:如果被指定,子进程的当前工作目录将被改变为`cwd`。
9、 `env`:一个字典,定义新进程的环境变量。
10、`universal_newlines`:如果`True`,则在此进程的输入/输出中使用通用换行符。
11、`startupinfo`和`creationflags`只在Windows上有效。
12、 `restore_signals`, `start_new_session`和`pass_fds`只在Unix上有效。
1、运行命令并获取输出
import subprocess
# 创建Popen对象
proc = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE)
# 获取命令的输出
out, err = proc.communicate()
# 打印命令的输出
print(out.decode('utf-8'))
2、使用shell方式运行命令
import subprocess
# 创建Popen对象
proc = subprocess.Popen('ls -l | grep .txt', shell=True, stdout=subprocess.PIPE)
# 获取命令的输出
out, err = proc.communicate()
# 打印命令的输出
print(out.decode('utf-8'))
3、使用环境变量:
import subprocess
import os
# 创建环境变量字典
env = os.environ.copy()
env['NEW_ENV_VAR'] = 'value'
# 创建Popen对象
proc = subprocess.Popen(['printenv', 'NEW_ENV_VAR'], env=env, stdout=subprocess.PIPE)
# 获取命令的输出
out, err = proc.communicate()
# 打印命令的输出
print(out.decode('utf-8'))
subprocess.Popen
类方法`Popen.poll()`方法用于检查子进程(由Popen实例代表)是否已经结束。
- 如果子进程已经结束,`poll()`方法将返回子进程的返回码。
- 如果子进程还在运行,`poll()`方法将返回`None`。
因此,你可以通过调用`poll()`方法来判断子进程是否还在运行。
这是一个使用示例:
import subprocess
import time
# 启动一个子进程
p = subprocess.Popen(['sleep', '5'])
# 每秒检查一次子进程的状态
while p.poll() is None:
print('Still running...')
time.sleep(1)
# 打印子进程的返回码
print('Return code:', p.poll())
在这个示例中,我们启动了一个会运行5秒的子进程。然后,我们每秒调用一次`poll()`方法来检查子进程是否还在运行。当子进程结束时,我们打印出子进程的返回码。
注意,当子进程结束后,你可以通过`Popen.returncode`属性获取子进程的返回码,这和调用`poll()`方法的效果是一样的。
`Popen.communicate()`方法用于和子进程进行交互。具体来说,它会发送输入,读取输出/错误,并等待子进程结束。
以下是参数的详细解释:
- `input`:要发送给子进程的数据。它应该是一个字节串,或者如果`Popen`对象的`text`或`universal_newlines`参数被设为`True`,也可以是一个字符串。如果你不需要发送数据,就不要使用这个参数。
- `timeout`:等待子进程结束的最大时间(以秒为单位)。如果在这个时间内子进程没有结束,就会引发`TimeoutExpired`异常。如果你不希望有时间限制,就不要使用这个参数。
`Popen.communicate()`方法会返回一个元组,包含子进程的标准输出和标准错误。
以下是一些使用示例:
- 读取子进程的输出:
import subprocess
# 创建Popen对象
proc = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE)
# 获取命令的输出
out, err = proc.communicate()
# 打印命令的输出
print(out.decode('utf-8'))
- 向子进程发送数据:
import subprocess
# 创建Popen对象
proc = subprocess.Popen(['cat'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
# 向命令发送数据,并获取命令的输出
out, err = proc.communicate(input=b'hello, world!')
# 打印命令的输出
print(out.decode('utf-8'))
- 使用超时:
import subprocess
# 创建Popen对象
proc = subprocess.Popen(['sleep', '10'], stdout=subprocess.PIPE)
try:
# 如果子进程在5秒内没有结束,就会引发TimeoutExpired异常
out, err = proc.communicate(timeout=5)
except subprocess.TimeoutExpired:
proc.kill()
out, err = proc.communicate()
`Popen.send_signal(signal)`方法用于发送信号给子进程。可以使用该方法来控制或者中断子进程。
`signal`参数应该是一个信号常量,如`signal.SIGTERM`或`signal.SIGKILL`。
以下是一个简单的使用示例:
import subprocess
import signal
import time
# 启动一个子进程
p = subprocess.Popen(['sleep', '10'])
# 等待一段时间
time.sleep(5)
# 发送SIGTERM信号给子进程
p.send_signal(signal.SIGTERM)
在这个示例中,我们首先启动了一个`sleep 10`子进程,然后等待5秒,接着发送了一个SIGTERM信号给子进程,告诉它正常退出。如果子进程在收到SIGTERM信号后没有立即退出,我们可以发送SIGKILL信号强制它退出。
注意:在Windows平台上,只有`signal.CTRL_C_EVENT`和`signal.CTRL_BREAK_EVENT`可以被`Popen.send_signal()`发送,但是Python可以接收所有信号。
`Popen.terminate()`方法用于发送一个终止信号给子进程。这个方法并不会立即停止子进程,而是给子进程一些时间来清理并正常退出。
这个方法在Unix和Windows上的行为略有不同:
- 在Unix上,`terminate()`方法会发送一个`SIGTERM`信号给子进程。
- 在Windows上,`terminate()`方法会调用`TerminateProcess()`函数来结束子进程。
这是一个使用示例:
import subprocess
import time
# 启动一个子进程
p = subprocess.Popen(['sleep', '10'])
# 等待一段时间
time.sleep(5)
# 终止子进程
p.terminate()
在这个示例中,我们首先启动了一个`sleep 10`子进程,然后等待5秒,接着调用`terminate()`方法来终止子进程。
注意:虽然`terminate()`方法可以终止子进程,但并不总是能确保子进程被清理。如果需要确保子进程被清理,你应该使用`Popen.communicate()`方法等待子进程结束。
`Popen.kill()`方法用于强制结束子进程。与`Popen.terminate()`方法不同,`kill()`方法发送的信号会立即结束子进程,不给子进程清理自身的机会。
这个方法在Unix和Windows上的行为略有不同:
- 在Unix上,`kill()`方法会发送一个`SIGKILL`信号给子进程。
- 在Windows上,`kill()`方法会调用`TerminateProcess()`函数来结束子进程。
这是一个使用示例:
import subprocess
import time
# 启动一个子进程
p = subprocess.Popen(['sleep', '10'])
# 等待一段时间
time.sleep(5)
# 强制结束子进程
p.kill()
在这个示例中,我们首先启动了一个`sleep 10`子进程,然后等待5秒,接着调用`kill()`方法来强制结束子进程。
注意:虽然`kill()`方法可以立即结束子进程,但并不总是能确保子进程被清理。如果需要确保子进程被清理,你应该使用`Popen.communicate()`方法等待子进程结束。
`Popen.stdout`是`subprocess.Popen`对象的一个属性,它代表子进程的标准输出流。
当你创建`Popen`对象时,如果你设置了`stdout=subprocess.PIPE`,那么`Popen.stdout`将是一个可读的流对象(实际上是一个`io.BufferedReader`对象),你可以从中读取子进程的输出。
以下是一个使用示例:
import subprocess
# 创建一个子进程,并打开其标准输出流
proc = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE)
# 从标准输出流中读取数据
for line in proc.stdout:
print('Got line:', line.decode('utf-8').strip())
# 等待子进程结束
proc.wait()
在这个示例中,我们创建了一个`ls -l`子进程,并打开了其标准输出流。然后,我们从标准输出流中读取了每一行数据,并打印出来。
注意,`Popen.stdout`只能被读取一次。如果你需要多次读取子进程的输出,你应该将输出保存到一个变量中。同时,如果你打开了子进程的标准输出流,你应该确保读取完所有的输出,否则子进程可能会被阻塞。如果你不需要子进程的输出,你可以设置`stdout=subprocess.DEVNULL`来忽略输出。
`Popen.stderr` 是 `subprocess.Popen` 对象的一个属性,它代表子进程的标准错误流。当你创建一个 `Popen` 对象时,如果设置了 `stderr=subprocess.PIPE`,那么 `Popen.stderr` 将是一个可读的流对象(实际上是一个 `io.BufferedReader` 对象),你可以从中读取子进程的错误输出。
以下是一个使用示例:
import subprocess
# 创建一个子进程,并打开其标准错误流
proc = subprocess.Popen(['ls', '/nonexistent'], stderr=subprocess.PIPE)
# 从标准错误流中读取数据
for line in proc.stderr:
print('Error line:', line.decode('utf-8').strip())
# 等待子进程结束
proc.wait()
在这个示例中,我们创建了一个 `ls /nonexistent` 子进程(这个命令会因为找不到目录而产生错误输出),并打开了其标准错误流。然后,我们从标准错误流中读取了每一行数据,并打印出来。
注意,`Popen.stderr` 只能被读取一次。如果你需要多次读取子进程的错误输出,你应该将输出保存到一个变量中。同时,如果你打开了子进程的标准错误流,你应该确保读取完所有的输出,否则子进程可能会被阻塞。如果你不需要子进程的错误输出,你可以设置 `stderr=subprocess.DEVNULL` 来忽略输出。
`Popen.pid`是`subprocess.Popen`对象的一个属性,它表示子进程的进程ID(PID)。
当你创建一个`Popen`对象(也就是启动一个子进程)后,你可以通过`Popen.pid`获取子进程的PID。
以下是一个使用示例:
import subprocess
# 创建一个子进程
proc = subprocess.Popen(['sleep', '10'])
# 打印子进程的PID
print('PID:', proc.pid)
在这个示例中,我们启动了一个`sleep 10`子进程,然后打印出了它的PID。
注意,PID是操作系统分配给每个进程的唯一标识符。你可以使用PID来监视或控制进程,比如查看进程的状态、发送信号给进程等。但是,PID是由操作系统管理的,你不应该试图修改PID。
`Popen.returncode`是`subprocess.Popen`对象的一个属性,它表示子进程的退出状态码。
当子进程正常结束时,`Popen.returncode`将是子进程的退出状态码,通常情况下,0表示成功,非0表示出错。如果子进程被信号终止,那么返回的将是负的信号值。
以下是一个使用示例:
import subprocess
# 创建一个子进程
proc = subprocess.Popen(['ls', '-l'])
# 等待子进程结束
proc.wait()
# 打印子进程的退出状态码
print('Return code:', proc.returncode)
在这个示例中,我们启动了一个`ls -l`子进程,然后等待它结束,最后打印出了它的退出状态码。
注意,在子进程还没有结束时,`Popen.returncode`的值是`None`。你可以使用`Popen.poll()`方法来检查子进程是否已经结束,如果子进程已经结束,`poll()`方法将返回退出状态码,否则返回`None`。
`subprocess.check_call()`函数用于运行一个命令,如果命令成功执行(即返回码为0),则返回0,否则抛出`CalledProcessError`异常。
subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None, **other_popen_kwargs)
1、`args`:要运行的命令和参数,可以是一个列表(如`["ls", "-l"]`),也可以是一个字符串(如`"ls -l"`)。如果`args`是一个字符串,那么需要设置`shell=True`。
2、`stdin`, `stdout`, `stderr`:分别表示子进程的标准输入、输出和错误流。默认情况下,这三个流都会被继承自父进程。如果你想重定向这些流,可以设置为`subprocess.PIPE`或一个文件对象。
3、 `shell`:如果设置为`True`,那么命令将在一个shell中运行,这意味着你可以使用shell特性,如通配符、管道等。默认情况下,`shell`是`False`。
-4、`cwd`:设置子进程的当前工作目录。
5、`timeout`:设置子进程的超时时间(单位是秒)。如果在这个时间内子进程没有结束,就会引发`TimeoutExpired`异常。
6、 `other_popen_kwargs`:其他传递给`Popen`构造函数的关键字参数。
1、 简单的命令:
import subprocess
# 运行ls -l命令
subprocess.check_call(["ls", "-l"])
2、 使用shell特性:
import subprocess
# 运行ls -l | grep .py命令
subprocess.check_call("ls -l | grep .py", shell=True)
3、 捕获输出:
import subprocess
# 运行ls -l命令,并捕获输出
with open('output.txt', 'w') as f:
subprocess.check_call(["ls", "-l"], stdout=f)
请注意,`check_call()`函数会等待命令结束。如果你需要异步执行命令,你应该使用`Popen`类。
subprocess.check_output()
函数用于运行一个命令,并返回命令的输出。如果命令成功执行(即返回码为0),则返回命令的输出,否则抛出CalledProcessError
异常。
subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, cwd=None, encoding=None, errors=None, universal_newlines=None, timeout=None, text=None, **other_popen_kwargs)
1、 `args`:要运行的命令和参数,可以是一个列表(如`["ls", "-l"]`),也可以是一个字符串(如`"ls -l"`)。如果`args`是一个字符串,那么需要设置`shell=True`。
2、`stdin`, `stderr`:分别表示子进程的标准输入和错误流。默认情况下,这两个流都会被继承自父进程。如果你想重定向这些流,可以设置为`subprocess.PIPE`或一个文件对象。
3、`shell`:如果设置为`True`,那么命令将在一个shell中运行,这意味着你可以使用shell特性,如通配符、管道等。默认情况下,`shell`是`False`。
4、`cwd`:设置子进程的当前工作目录。
5、`encoding`, `errors`:这两个参数用于控制如何解码命令的输出。如果设置了这两个参数,那么命令的输出将被解码为字符串,否则输出为字节串。
6、`universal_newlines`:这个参数已经被`text`参数取代,不建议使用。
7、`timeout`:设置子进程的超时时间(单位是秒)。如果在这个时间内子进程没有结束,就会引发`TimeoutExpired`异常。
8、`text`:如果设置为`True`,那么命令的输出将被解码为字符串,否则输出为字节串。
9、 `other_popen_kwargs`:其他传递给`Popen`构造函数的关键字参数。
1、简单的命令:
import subprocess
# 运行ls -l命令,并获取输出
output = subprocess.check_output(["ls", "-l"], text=True)
print(output)
2、使用shell特性:
import subprocess
# 运行ls -l | grep .py命令,并获取输出
output = subprocess.check_output("ls -l | grep .py", shell=True, text=True)
print(output)
请注意,`check_output()`函数会等待命令结束。如果你需要异步执行命令,你应该使用`Popen`类。