31 个版本
0.2.9 | 2022 年 5 月 15 日 |
---|---|
0.2.8 | 2021 年 9 月 21 日 |
0.2.7 | 2021 年 5 月 13 日 |
0.2.6 | 2020 年 9 月 21 日 |
0.1.10 | 2017 年 3 月 18 日 |
#29 在 操作系统 分类中
每月下载量:388,214
用于 385 个crate(其中 147 个直接使用)
175KB
3.5K SLoC
subprocess
subprocess
库提供了执行和与外部进程及管道交互的功能,灵感来源于 Python 的 subprocess
模块。该库托管在 crates.io 上,API 文档在 docs.rs 上。
功能
此库关于使用可选的重定向标准输入、输出和错误来启动外部进程。它涵盖了与标准库模块 std::process
类似的内容,但具有额外的功能
-
communicate 方法族,用于在同时向其标准输入馈送数据的同时,无死锁地捕获子进程的输出/错误到内存中。捕获支持可选的超时和读取大小限制。
-
将多个命令连接到操作系统级别的管道中。
-
灵活的重定向选项,例如将标准流连接到任意文件,或者合并输出流,如 shell 的
2>&1
和1>&2
运算符。 -
非阻塞和超时方法等待进程:
poll
、wait
和wait_timeout
。
该库对外部crate的依赖最少,仅需要Unix系统上的libc
和Windows系统上的winapi
。它旨在在类Unix平台以及较新的Windows平台上工作。它定期在Linux、MacOS和Windows上进行测试。
API概述
API分为两部分:低级的Popen
API,类似于Python的subprocess.Popen
,以及用于方便创建命令和管道的高级API。两者可以混合使用,因此可以使用构建器创建Popen
实例,然后直接与它们一起工作。
Popen
大致遵循Python的subprocess
模块,但并非字面翻译。其中一些变化是为了适应两种语言之间的差异,例如Rust中没有默认和关键字参数,而另一些则是利用Rust更高级的类型系统或额外的功能,例如所有权系统和Drop
特性。Python的实用函数,如subprocess.run
,没有包括在内,因为它们可以使用构建器模式更好地表达。
高级API提供了一个优雅的过程和管道创建接口,以及方便的捕获输出和退出状态的方法。
示例
启动和重定向
执行命令并等待其完成
let exit_status = Exec::cmd("umount").arg(dirname).join()?;
assert!(exit_status.success());
为了防止引号问题和注入攻击,除非明确请求,否则子进程不会启动shell。要使用操作系统shell执行命令,如C的system
,请使用Exec::shell
Exec::shell("shutdown -h now").join()?;
启动子进程并获取其输出作为Read
trait对象,类似于C的popen
let stream = Exec::cmd("find /").stream_stdout()?;
// Call stream.read_to_string, construct io::BufReader(stream) and iterate it
// by lines, etc...
捕获命令的输出
let out = Exec::cmd("ls")
.stdout(Redirection::Pipe)
.capture()?
.stdout_str();
将标准错误重定向到标准输出,并将它们捕获到一个字符串中
let out_and_err = Exec::cmd("ls")
.stdout(Redirection::Pipe)
.stderr(Redirection::Merge)
.capture()?
.stdout_str();
向命令提供一些输入并读取其输出
let out = Exec::cmd("sort")
.stdin("b\nc\na\n")
.stdout(Redirection::Pipe)
.capture()?
.stdout_str();
assert_eq!(out, "a\nb\nc\n");
将stdin
连接到一个打开的文件也可以。
管道
Popen
对象支持将输入和输出连接到任意打开的文件,包括其他Popen
对象。这可以用来形成进程的管道。构建器API会在Exec
对象的|
操作符上自动执行。
执行管道并返回最后一个命令的退出状态
let exit_status =
(Exec::shell("ls *.bak") | Exec::cmd("xargs").arg("rm")).join()?;
捕获管道的输出
let dir_checksum = {
Exec::shell("find . -type f") | Exec::cmd("sort") | Exec::cmd("sha1sum")
}.capture()?.stdout_str();
低级Popen类型
let mut p = Popen::create(&["command", "arg1", "arg2"], PopenConfig {
stdout: Redirection::Pipe, ..Default::default()
})?;
// Since we requested stdout to be redirected to a pipe, the parent's
// end of the pipe is available as p.stdout. It can either be read
// directly, or processed using the communicate() method:
let (out, err) = p.communicate(None)?;
// check if the process is still alive
if let Some(exit_status) = p.poll() {
// the process has finished
} else {
// it is still running, terminate it
p.terminate()?;
}
查询和终止
检查先前启动的进程是否仍在运行
let mut p = Exec::cmd("sleep").arg("2").popen()?;
thread::sleep(Duration::new(1, 0));
if p.poll().is_none() {
// poll() returns Some(exit_status) if the process has completed
println!("process is still running");
}
给进程1秒钟的时间运行,如果它在那之前没有完成,就杀死它。
let mut p = Exec::cmd("sleep").arg("2").popen()?;
if let Some(status) = p.wait_timeout(Duration::new(1, 0))? {
println!("process finished as {:?}", status);
} else {
p.kill()?;
p.wait()?;
println!("process killed");
}
许可证
subprocess
根据MIT许可证和Apache许可证(版本2.0)的条款进行分发。有关详细信息,请参阅LICENSE-APACHE和LICENSE-MIT。贡献更改被视为表示同意这些许可条款。