Поиск исполняемого файла в PATH с Rust

92
10

В Python я могу:


from distutils import spawn

cmd = spawn.find_executable("commandname")


Я попробовал что-то вроде кода ниже, но он предполагает, что вы используете unix-подобную систему с /usr/bin/which доступной (также она включает в себя выполнение внешней команды, которую я хочу избежать):


use std::process::Command;

let output = Command::new("which")
.arg("commandname")
.unwrap_or_else(|e| /* handle error here */)


Каков самый простой способ сделать это в Rust?

спросил(а) 2021-01-19T15:34:48+03:00 9 месяцев назад
1
Решение
92

Я бы, вероятно, захватил переменную окружения и повторил ее, возвращая первый путь соответствия:


use std::env;
use std::path::{Path, PathBuf};

fn find_it<P>(exe_name: P) -> Option<PathBuf>
where P: AsRef<Path>,
{
env::var_os("PATH").and_then(|paths| {
env::split_paths(&paths).filter_map(|dir| {
let full_path = dir.join(&exe_name);
if full_path.is_file() {
Some(full_path)
} else {
None
}
}).next()
})
}

fn main() {
println!("{:?}", find_it("cat"));
println!("{:?}", find_it("dog"));
}


Это, вероятно, уродливо для Windows, поскольку вам нужно добавить .exe к исполняемому имени. Он также потенциально может быть расширен только для возвращаемых элементов, которые являются исполняемыми, что также является кодом, специфичным для платформы.


Пересматривая Python реализацию, похоже, что они также поддерживают абсолютный путь передачи. Это зависит от вас, если функция должна поддерживать это или нет.


Быстрый поиск по crates.io возвратил один ящик, который может быть полезен: quale, хотя в настоящее время он говорит

работает только в Unix-подобных операционных системах.



Меня не удивит, узнав, что есть другие.


Вот какой-то уродливый код, который добавляет .exe в конец, если он отсутствует, но только в Windows.


#[cfg(not(target_os = "windows"))]
fn enhance_exe_name(exe_name: &Path) -> Cow<Path> {
exe_name.into()
}

#[cfg(target_os = "windows")]
fn enhance_exe_name(exe_name: &Path) -> Cow<Path> {
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;

let raw_input: Vec<_> = exe_name.as_os_str().encode_wide().collect();
let raw_extension: Vec<_> = OsStr::new(".exe").encode_wide().collect();

if raw_input.ends_with(&raw_extension) {
exe_name.into()
} else {
let mut with_exe = exe_name.as_os_str().to_owned();
with_exe.push(".exe");
PathBuf::from(with_exe).into()
}
}

// At the top of the `find_it` function:
// let exe_name = enhance_exe_name(exe_name.as_ref());

ответил(а) 2021-01-19T15:34:48+03:00 9 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема