如何将 which(1) 与系统的默认 $PATH 一起使用?

geo*_*ock 5 path environment-variables which

我想使用which系统的默认路径,忽略用户 shell 配置文件中的任何修饰。

动机

我正在尝试编写一个脚本来查找系统的 Ruby 二进制文件。许多 Ruby 开发人员使用 Ruby 版本管理器,它会~/.rvm/bin在他们的$PATH. 我想绕过这个并使用系统附带的 Ruby 版本,或者是通过系统的包管理器安装的。

当前解决方案

这是我迄今为止尝试过的:

$ env -i sh -c "which ruby"
Run Code Online (Sandbox Code Playgroud)

这没有输出,并以 1 退出。我希望它可以工作,因为路径包含/usr/bin,并且我的系统附带了一个 Ruby 二进制文件/usr/bin/ruby

$ env -i sh -c "echo \$PATH"
/usr/gnu/bin:/usr/local/bin:/bin:/usr/bin:.
$ which -a ruby
# ...
/usr/bin/ruby
Run Code Online (Sandbox Code Playgroud)

一些额外的细节:

  • env -s bash -c "which ruby" 也没有找到任何东西。
  • env -i zsh -c "which ruby"确实找到了/usr/bin/ruby,但我不能依赖zsh.
  • 使用完整路径which(以确保我使用的是二进制文件,而不是内置的 shell)没有任何区别。

我的环境

我在 OS X 上用 Bash 编写这个,但希望它可以移植到其他 shell 和操作系统。

Mik*_*kel 5

command -pv 使用“PATH 的默认值”。

$ which ruby
/home/mikel/.rvm/rubies/ruby-1.9.3-p484/bin/ruby

$ command -pv ruby
/usr/bin/ruby
Run Code Online (Sandbox Code Playgroud)

不幸的是,这在 中不起作用zsh,因此根据 Stephane 的评论,我们可以使用getconf PATH

$ PATH=$(getconf PATH) which ruby
Run Code Online (Sandbox Code Playgroud)

command -v代替which,如为什么不使用“which”中所推荐的那样?那用什么?

$ PATH=$(getconf PATH) command -v ruby
Run Code Online (Sandbox Code Playgroud)

这些方法的缺点是,如果系统管理员安装的系统级版本为说/usr/local/bin/opt/local/bin,所有用户必须在PATH(例如,通过/etc/profile/etc/environment或类似的),上面可能不会发现它。

在你的具体情况下,我建议尝试一些特定于 Ruby 的东西。以下是一些可能有效的想法:

  1. 过滤掉用户主目录(和相对路径)中的版本:

    (
        IFS=:
        set -f
        for dir in $PATH; do
            case $dir/ in
                "$HOME/"*) ;;
                /*/)
                    if [ -f "$dir/ruby" ] && [ -x "$dir/ruby" ]; then
                        printf '%s\n' "$dir/ruby"
                        break
                    fi;;
            esac
        done
    )
    
    Run Code Online (Sandbox Code Playgroud)
  2. 过滤掉rvm目录下的版本

    (
        IFS=:
        set -f
        for dir in $PATH; do
            case $dir/ in
                "$rvmpath/"*) ;;
                /*/)
                    if [ -f "$dir/ruby" ] && [ -x "$dir/ruby" ]; then
                        printf '%s\n' "$dir/ruby"
                        break
                    fi;;
            esac
        done
    )
    
    Run Code Online (Sandbox Code Playgroud)
  3. 过滤掉可写的红宝石(最后的手段,假设不是以 root 身份运行)

    (
        IFS=:
        set -f
        for dir in $PATH; do
            case $dir/ in
                /*/)
                    ruby=$dir/ruby
                    if [ -f "$ruby" ] && [ -x "$ruby" ] && [ ! -w "$ruby" ]; then
                        printf '%s\n' "$ruby"
                        break
                    fi;;
            esac
        done
    )
    
    Run Code Online (Sandbox Code Playgroud)
  4. rvmchruby

    (
        rvm system
        chruby system
        command -v ruby
    )
    
    Run Code Online (Sandbox Code Playgroud)

最后一种方法是rvm选择默认的 Ruby,但我们在子 shell 中执行此操作,以便之后恢复用户首选的 Ruby。(chruby部分未经测试。)