#execute-command #stdin #process #input-output #command #redirect #child-process

bin+lib subprocess

受 Python 的 subprocess 模块启发的子进程和管道执行,具有 Rust 特定的扩展

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操作系统 分类中

Download history 94982/week @ 2024-04-23 88393/week @ 2024-04-30 96632/week @ 2024-05-07 93287/week @ 2024-05-14 91639/week @ 2024-05-21 103326/week @ 2024-05-28 93618/week @ 2024-06-04 91402/week @ 2024-06-11 86744/week @ 2024-06-18 87087/week @ 2024-06-25 84112/week @ 2024-07-02 96405/week @ 2024-07-09 94439/week @ 2024-07-16 88576/week @ 2024-07-23 95841/week @ 2024-07-30 91768/week @ 2024-08-06

每月下载量:388,214
用于 385crate(其中 147 个直接使用)

Apache-2.0/MIT

175KB
3.5K SLoC

subprocess

Build Status docs.rs

subprocess 库提供了执行和与外部进程及管道交互的功能,灵感来源于 Python 的 subprocess 模块。该库托管在 crates.io 上,API 文档在 docs.rs 上。

功能

此库关于使用可选的重定向标准输入、输出和错误来启动外部进程。它涵盖了与标准库模块 std::process 类似的内容,但具有额外的功能

  • communicate 方法族,用于在同时向其标准输入馈送数据的同时,无死锁地捕获子进程的输出/错误到内存中。捕获支持可选的超时和读取大小限制。

  • 将多个命令连接到操作系统级别的管道中。

  • 灵活的重定向选项,例如将标准流连接到任意文件,或者合并输出流,如 shell 的 2>&11>&2 运算符。

  • 非阻塞和超时方法等待进程:pollwaitwait_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-APACHELICENSE-MIT。贡献更改被视为表示同意这些许可条款。

依赖关系