Rust代码执行库execute的使用,execute提供高效安全的代码执行与动态加载功能

Rust代码执行库execute的使用,execute提供高效安全的代码执行与动态加载功能

execute库用于扩展Command,以便更轻松地执行程序。

使用

use std::process::Command;
use execute::Execute;
// ...

验证程序

由于Command用于生成命令进程,而执行的程序是外部的,可能不存在或不是我们预期的程序,我们通常需要在运行时验证外部程序。

execute_check_exit_status_code方法可用于执行命令并检查其退出状态。例如:

use std::process::Command;
use execute::Execute;

const FFMPEG_PATH: &str = "/path/to/ffmpeg";

let mut first_command = Command::new(FFMPEG_PATH);
first_command.arg("-version");

if first_command.execute_check_exit_status_code(0).is_err() {
    eprintln!("The path `{}` is not a correct FFmpeg executable binary file.", FFMPEG_PATH);
}

执行并获取退出状态

use std::process::Command;
use execute::Execute;

const FFMPEG_PATH: &str = "/path/to/ffmpeg";

let mut command = Command::new(FFMPEG_PATH);
command.arg("-i");
command.arg("/path/to/media-file");
command.arg("/path/to/output-file");

if let Some(exit_code) = command.execute().unwrap() {
    if exit_code == 0 {
        println!("Ok.");
    } else {
        eprintln!("Failed.");
    }
} else {
    eprintln!("Interrupted!");
}

执行并获取输出

输出到屏幕

use std::process::Command;
use execute::Execute;

const FFMPEG_PATH: &str = "/path/to/ffmpeg";

let mut command = Command::new(FFMPEG_PATH);
command.arg("-i");
command.arg("/path/to/media-file");
command.arg("/path/to/output-file");

let output = command.execute_output().unwrap();

if let Some(exit_code) = output.status.code() {
    if exit_code == 0 {
        println!("Ok.");
    } else {
        eprintln!("Failed.");
    }
} else {
    eprintln!("Interrupted!");
}

输出到内存(捕获)

use std::process::{Command, Stdio};
use execute::Execute;

const FFMPEG_PATH: &str = "/path/to/ffmpeg";

let mut command = Command::new(FFMPEG_PATH);
command.arg("-i");
command.arg("/path/to/media-file");
command.arg("/path/to/output-file");

command.stdout(Stdio::piped());
command.stderr(Stdio::piped());

let output = command.execute_output().unwrap();

if let Some(exit_code) = output.status.code() {
    if exit_code == 0 {
        println!("Ok.");
    } else {
        eprintln!("Failed.");
    }
} else {
    eprintln!("Interrupted!");
}

println!("{}", String::from_utf8(output.stdout).unwrap());
println!("{}", String::from_utf8(output.stderr).unwrap());

执行并输入数据

输入内存数据

use std::process::{Command, Stdio};
use execute::Execute;

let mut bc_command = Command::new("bc");
bc_command.stdout(Stdio::piped());

let output = bc_command.execute_input_output("2^99\n").unwrap();

println!("Answer: {}", String::from_utf8(output.stdout).unwrap().trim_end());

从读取器输入

use std::process::{Command, Stdio};
use std::fs::File;
use execute::Execute;

let mut cat_command = Command::new("cat");
cat_command.stdout(Stdio::piped());

let mut file = File::open("Cargo.toml").unwrap();

let output = cat_command.execute_input_reader_output(&mut file).unwrap();

println!("{}", String::from_utf8(output.stdout).unwrap());

默认缓冲区大小为256字节。如果要更改,可以使用_reader_output2_reader2方法并显式定义长度。

例如,将缓冲区大小更改为4096字节:

use std::process::{Command, Stdio};
use std::fs::File;
use execute::generic_array::typenum::U4096;
use execute::Execute;

let mut cat_command = Command::new("cat");
cat_command.stdout(Stdio::piped());

let mut file = File::open("Cargo.toml").unwrap();

let output = cat_command.execute_input_reader_output2::<U4096>(&mut file).unwrap();

println!("{}", String::from_utf8(output.stdout).unwrap());

执行多个命令并将它们管道连接

use std::process::{Command, Stdio};
use execute::Execute;

let mut command1 = Command::new("echo");
command1.arg("HELLO WORLD");

let mut command2 = Command::new("cut");
command2.arg("-d").arg(" ").arg("-f").arg("1");

let mut command3 = Command::new("tr");
command3.arg("A-Z").arg("a-z");

command3.stdout(Stdio::piped());

let output = command1.execute_multiple_output(&mut [&mut command2, &mut command3]).unwrap();

assert_eq!(b"hello\n", output.stdout.as_slice());

在当前shell中运行命令字符串

shell函数可用于创建带有单个命令字符串而不是程序名称和分散参数的Command实例。

use std::process::{Command, Stdio};
use execute::{Execute, shell};

let mut command = shell("cat /proc/meminfo");
command.stdout(Stdio::piped());

let output = command.execute_output().unwrap();

println!("{}", String::from_utf8(output.stdout).unwrap());

在运行时解析命令字符串

command函数可用于创建带有单个命令字符串而不是程序名称和分散参数的Command实例。shell函数和command函数的区别在于前者由当前shell解释,而后者由本crate解析。

use std::process::{Command, Stdio};
use execute::{Execute, command};

let mut command = command("cat '/proc/meminfo'");
command.stdout(Stdio::piped());

let output = command.execute_output().unwrap();

println!("{}", String::from_utf8(output.stdout).unwrap());

在编译时解析命令字符串

command!宏可用于创建带有单个命令字符串字面量而不是程序名称和分散参数的Command实例。

use std::process::{Command, Stdio};
use execute::Execute;

let mut command = execute::command!("cat '/proc/meminfo'");
command.stdout(Stdio::piped());

let output = command.execute_output().unwrap();

println!("{}", String::from_utf8(output.stdout).unwrap());

通过单独提供参数创建Command实例

command_args!宏可用于通过单独提供程序名称和参数来创建Command实例。程序名称和参数可以是非字面量。

use std::process::{Command, Stdio};
use execute::Execute;

let mut command = execute::command_args!("cat", "/proc/meminfo");
command.stdout(Stdio::piped());

let output = command.execute_output().unwrap();

println!("{}", String::from_utf8(output.stdout).unwrap());

完整示例

以下是一个完整的示例,展示了如何使用execute库执行命令并处理输出:

use std::process::{Command, Stdio};
use execute::{Execute, shell};

fn main() {
    // 使用shell函数执行命令
    let mut command = shell("ls -l");
    command.stdout(Stdio::piped());
    
    // 执行命令并获取输出
    let output = command.execute_output().unwrap();
    
    // 检查退出状态
    if let Some(exit_code) = output.status.code() {
        if exit_code == 0 {
            // 成功执行,打印输出
            println!("Command executed successfully:");
            println!("{}", String::from_utf8(output.stdout).unwrap());
        } else {
            // 命令执行失败
            eprintln!("Command failed with exit code: {}", exit_code);
            eprintln!("Error output: {}", String::from_utf8(output.stderr).unwrap());
        }
    } else {
        // 命令被中断
        eprintln!("Command was interrupted!");
    }
    
    // 验证程序是否存在
    let mut check_cmd = Command::new("python3");
    check_cmd.arg("--version");
    if check_cmd.execute_check_exit_status_code(0).is_err() {
        eprintln!("Python3 is not installed or not in PATH");
    }
}

这个示例展示了如何:

  1. 使用shell函数执行命令
  2. 捕获命令输出
  3. 检查命令退出状态
  4. 处理成功和失败情况
  5. 验证程序是否存在

execute库提供了强大而灵活的方式来执行外部命令,并处理各种执行场景。


1 回复

Rust代码执行库execute的使用指南

execute是一个Rust库,提供了高效且安全的代码执行与动态加载功能。它特别适合需要动态执行代码或加载库的场景,同时保持了Rust的安全保证。

主要特性

  • 安全地执行动态代码
  • 高效的内存管理
  • 支持多种执行模式
  • 简单的API设计
  • 跨平台支持

安装

Cargo.toml中添加依赖:

[dependencies]
execute = "0.3"

基本用法

执行外部命令

use execute::Execute;

fn main() {
    let mut command = execute::command!("echo", "Hello, world!");
    
    if let Some(exit_code) = command.execute().unwrap() {
        println!("Command exited with code {}", exit_code);
    } else {
        println!("Command was terminated by a signal");
    }
}

动态加载库

use execute::Library;

fn main() {
    // 加载动态库
    let lib = Library::load("path/to/library.so").unwrap();
    
    // 获取函数指针
    let func: execute::Symbol<unsafe extern "C" fn(i32) -> i32> = 
        unsafe { lib.symbol("function_name") }.unwrap();
    
    // 调用函数
    let result = unsafe { func(42) };
    println!("Result: {}", result);
}

高级用法

带超时的命令执行

use execute::Execute;
use std::time::Duration;

fn main() {
    let mut command = execute::command!("sleep", "10");
    command.timeout(Duration::from_secs(5));
    
    match command.execute() {
        Ok(Some(code)) => println!("Command exited with {}", code),
        Ok(None) => println!("Command terminated by signal"),
        Err(e) => println!("Command failed: {}", e),
    }
}

捕获命令输出

use execute::Execute;

fn main() {
    let mut command = execute::command!("ls", "-l");
    let output = command.execute_output().unwrap();
    
    println!("Status: {}", output.status);
    println!("Stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("Stderr: {}", String::from_utf8_lossy(&output.stderr));
}

完整示例代码

下面是一个结合了基本用法和高级用法的完整示例:

use execute::{Execute, Library};
use std::time::Duration;

fn main() {
    // 示例1:执行简单命令
    println!("=== 示例1:执行简单命令 ===");
    let mut cmd1 = execute::command!("echo", "Hello from execute!");
    if let Some(code) = cmd1.execute().unwrap() {
        println!("命令退出码: {}", code);
    }

    // 示例2:带超时的命令执行
    println!("\n=== 示例2:带超时的命令执行 ===");
    let mut cmd2 = execute::command!("sleep", "3");
    cmd2.timeout(Duration::from_secs(1));
    match cmd2.execute() {
        Ok(Some(c)) => println!("完成执行,退出码: {}", c),
        Ok(None) => println!("命令被信号终止"),
        Err(e) => println!("执行失败: {}", e),
    }

    // 示例3:捕获命令输出
    println!("\n=== 示例3:捕获命令输出 ===");
    let mut cmd3 = execute::command!("ls", "-l");
    let output = cmd3.execute_output().unwrap();
    println!("命令输出:\n{}", String::from_utf8_lossy(&output.stdout));

    // 示例4:动态库加载
    println!("\n=== 示例4:动态库加载 ===");
    #[cfg(unix)]
    {
        // 注意:实际使用时需要替换为有效的动态库路径
        if let Ok(lib) = Library::load("/path/to/valid/library.so") {
            unsafe {
                if let Ok(func) = lib.symbol::<unsafe extern "C" fn()>("some_function") {
                    println!("成功获取函数指针");
                    func();
                }
            }
        }
    }
}

安全注意事项

  1. 动态加载代码时要确保来源可信
  2. 处理外部命令时要注意注入风险
  3. 使用unsafe块时要遵循Rust的安全准则

性能提示

  • 对于频繁执行的命令,考虑重用Command实例
  • 大量输出时使用流式处理而非一次性读取
  • 考虑使用spawn而非execute进行异步执行

execute库为Rust提供了强大而安全的动态执行能力,适合构建需要灵活性的系统工具和应用。

回到顶部