#子进程 #进程 # #文件描述符 #环境变量 #管道 #命令

creche

标准库中 std::process::Command 和相关类型的替代品。可以运行单个进程和进程管道,并为每个子进程配置文件描述符和环境。

5 个版本

0.2.1 2024年7月1日
0.2.0 2024年6月30日
0.1.4 2024年6月13日

#198并发

MIT/Apache

46KB
776

Creche

配置、运行和监视单个子进程或整个进程管道。将这些进程的文件描述符重定向到和从这些进程。控制环境变量。

Creche 是标准库中的 Command 和其他相关功能的替代品。

目标

  • 最小依赖
  • 没有宏,只有常规 Rust 语法
  • 保持简单易用,同时不牺牲可配置性

限制

  • 仅限 Linux
  • 不支持 nostd
  • 尚未处理子进程权限/能力
  • 尚未支持异步

如何使用

ChildBuilderSimplePipelineBuilder 类型是顶级导出,因此许多常见用例都可以通过简单的 use

use creche::*;

阅读 变更日志 了解 API 的重大更改。

示例

cat 的输出读取到 String

// configure the child process
let mut cmd = ChildBuilder::new("cat");
cmd.arg("somefile")
    .redirect21(); // redirect stderr to stdout
let read_fd = cmd.pipe_from_stdout();

// run it
let mut child = cmd.spawn();

// read stdout from the child process
let f = std::fs::File::from(read_fd);
let output = std::io::read_to_string(f)?;
println!("output is: {:?}", output);
println!("exit status: {:?}", child.wait());

向子进程写入数据

let mut cmd = creche::ChildBuilder::new("tr");
cmd.arg("[:lower:]")
    .arg("[:upper:]");
let write_fd = cmd.pipe_to_stdin();
let child = cmd.spawn();

// write some data
let mut f = std::fs::File::from(write_fd);
writeln!(f, "this is a test message");
// don't forget to close your fd. Or at least .flush() the thing.
drop(f);

println!("child exit: {:?}", child.wait());

设置 fzf 在仅包含 PATH、HOME 和 FZF_DEFAULT_COMMAND 的环境中运行。然后运行它并获取其输出

// configure the environment
let mut env = envconfig::EnvironmentBuilder::new();
env.keep("PATH")
    .set("HOME", "/etc")
    // Note: $HOME is expanded in the shell spawned by fzf.
    // It's not creche magic.
    .set("FZF_DEFAULT_COMMAND", "ls -1 $HOME");
// configure the child process
let mut cmd = ChildBuilder::new("fzf");
cmd.arg("-m")
    .arg(r#"--preview=bat $HOME/{}"#)
    .set_env(env.realize());
let read_fd = cmd.pipe_from_stdout();

// run it
let child = cmd.spawn();

// read the result
let mut f = std::fs::File::from(read_fd);
let output = std::io::read_to_string(f)?;
println!("output is: {:?}", output);
println!("exit status: {:?}", child.wait());

ls 的输出通过 sort 通过 tr。将所有这些的 stderr 重定向到 /dev/null

let mut ls_cmd = ChildBuilder::new("ls");
ls_cmd.arg("-1");
let mut sort_cmd = ChildBuilder::new("sort");
sort_cmd.arg("-r");
let mut tr_cmd = ChildBuilder::new("tr");
tr_cmd.arg("[:lower:]");
tr_cmd.arg("[:upper:]");

let mut pipeline = SimplePipelineBuilder::new();
let mut children = pipeline
    .add_builder(ls_cmd)
    .add_builder(sort_cmd)
    .add_builder(tr_cmd)
    .quiet()
    .spawn();

println!("{:?}", children.wait());

在另一个线程中发送 SIGTERM 信号并阻塞等待子进程的 .wait()

// sleep for a few seconds
let mut cmd = ChildBuilder::new("sleep");
cmd.arg("6");
println!("sleeping for six seconds");
let child = cmd.spawn();

// get a "handle" to the child process so that we may signal it
let handle = child.get_handle();

// start a thread that sends SIGTERM after a short pause
std::thread::spawn( move || {
    std::thread::sleep(std::time::Duration::from_secs(2));
    println!("sending SIGTERM from thread");
    _ = handle.terminate();
});

// collect the child exit status
println!("child exit: {:?}", child.wait());

依赖关系

~1.5MB
~35K SLoC