【问题标题】:Finding executable in PATH with Rust使用 Rust 在 PATH 中查找可执行文件
【发布时间】:2016-05-28 12:15:11
【问题描述】:

在 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 中最简单的方法是什么?

【问题讨论】:

    标签: rust


    【解决方案1】:

    我找到了一个解决问题的板条箱:which。它包括 Windows 支持,甚至包括 PATHEXT

    【讨论】:

      【解决方案2】:

      我可能会抓取环境变量并遍历它,返回第一个匹配路径:

      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 implementation,似乎它们也支持传递的绝对路径。函数是否支持该功能取决于您。

      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());
      

      【讨论】:

      • 盲目使用.exe 并不真的正确。您应该使用PATHEXT 环境变量,这是一个; 分隔的被认为是“可执行”的文件扩展名列表。遗憾的是,您必须小心,因为 CreateProcess(这是 Rust 的 Command 类型所支持的,AFAIK)仅支持本机可执行类型,因此不能像在 UNIX 上那样使用它(例如 调用 shell 脚本)。因此,除非您还打算使用 ShellExecute(Rust 不使用 I-don't-know-why)编写自己的代码,否则您可能应该限制自己使用 .COM;.EXE
      • @DK。跨平台工作很辛苦!不管它值多少钱,这里的代码都模仿了 Python 正在做的事情,尽管我不知道 Windows 对 Python 的支持有多么出色。也许我们应该把它提交到一个板条箱(比如 quale?)。
      • 是的,我在写完之后意识到(当我用完字符时)如果不编写实际的 Win32 代码,在 Rust 中真的没有办法正确做到这一点,因为即使您正确找到commandname.py 或其他内容,您也无法实际调用它。我想这就是你在执行脚本时得到的结果是 shell 功能而不是内核功能......
      猜你喜欢
      • 1970-01-01
      • 2017-04-28
      • 1970-01-01
      • 2019-01-16
      • 2015-01-25
      • 2015-05-19
      • 1970-01-01
      • 1970-01-01
      • 2015-07-21
      相关资源
      最近更新 更多