システムの基本 $PATH で which(1) を使用するには?

システムの基本 $PATH で which(1) を使用するには?

whichユーザーシェル設定ファイルの変更を無視し、システムのデフォルトパスを使用したいと思います。

やる気

私のシステムのRubyバイナリを見つけるためのスクリプトを書こうとしています。多くのRuby開発者はRubyバージョンマネージャを使用し、それ自身~/.rvm/bin$PATH

現在のソリューション

これが私が今まで試したことです:

$ env -i sh -c "which ruby"

これは出力を提供せずに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

いくつかの追加の詳細:

  • env -s bash -c "which ruby"何も見つかりませんでした。
  • env -i zsh -c "which ruby"実際に見つけ/usr/bin/rubyたが信じられないzsh
  • フルパスを使用するとwhich(シェル組み込みではなくバイナリを使用していることを確認するために)、違いはありません。

私の環境

私はOS XのBashでこの記事を書いていますが、他のシェルやオペレーティングシステムに移植できることを願っています。

答え1

command -pv「PATHのデフォルト値」を使用してください。

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

$ command -pv ruby
/usr/bin/ruby

残念ながらこれはうまくいかないので、zshStephaneの意見に基づいて以下を使用できますgetconf PATH

$ PATH=$(getconf PATH) which ruby

またはcommand -v提案されているようにwhich使用してください。「which」を使わないのはなぜですか?それでは何を使うべきですか?

$ PATH=$(getconf PATH) command -v ruby

この方法の欠点は、システム管理者が/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
    )
    
  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
    )
    
  3. 書き込み可能なルビーフィルタリング(最後の手段、ルートとして実行されないと仮定)

    (
        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
    )
    
  4. 尋ねてrvmくださいchruby。しばらくしてください。

    (
        rvm system
        chruby system
        command -v ruby
    )
    

最後の方法はデフォルトのrvmRubyを選択しますが、後でユーザーが好むRubyを復元できるようにサブシェルでこれを行います。 (chruby部分的にテストされていません。)

答え2

$PATHサブシェルで明示的に値を設定すると、問題が解決します。

env -i sh -c "PATH=\$PATH which ruby"

$inはエスケープされます。これは$PATH、コマンドを実行する前にサブシェル$PATHコマンドが親シェルの値に置き換えられないことを意味します(単一引用符を使用して実行することもできます)。$PATH

この場合、これがなぜ必要なのか知りたいです。

答え3

通常、このコマンドを使用したくありませんwhich。 Bashではtypeorコマンドを使用する必要がありますcommand。理由については、次のQ&Aをご覧ください。「which」を使わないのはなぜですか?それでは何を使うべきですか?

はい

$ type -a ls
ls is aliased to `ls --color=auto'
ls is /bin/ls

またはこれ:

$ type -a vim
vim is /usr/bin/vim

またはこれ:

$ command -v ls
alias ls='ls --color=auto'

またはこれ:

$ command -v vim
/usr/bin/vim

Bashのマニュアルページから。

タイプ抜粋

type [-aftpP] name [name ...]
     With no options, indicate how each name would be interpreted if used as a
     command name.  If the -t option is used, type  prints a  string  which  is
     one  of  alias, keyword, function, builtin, or file if name is an alias,
     shell reserved word, function, builtin, or disk file, respectively.  If the
     name is not found, then nothing is  printed, and  an exit status of false
     is returned.  If the -p option is used, type either returns the name of the
     disk file that would be executed if name were specified as a command name,
     or nothing if ``type -t name'' would  not  return file.   The  -P  option
     forces a PATH search for each name, even if ``type -t name'' would not
     return file.  If a command is hashed, -p and -P print the hashed value, not
     necessarily the file that appears first in PATH.  If  the -a option is used,
     type prints all of the places that contain an executable named name.  This
     includes aliases and functions, if and only if the -p option is not also
     used.  The table of hashed commands  is  not  consulted  when using  -a.
     The -f option suppresses shell function lookup, as with the command
     builtin.  type returns true if all of the arguments are found, false if
     any are not found.

順序による抜粋

   command [-pVv] command [arg ...]
         Run command with args suppressing the normal shell function lookup.
         Only builtin commands or commands found in the PATH are executed.  If
         the -p option is given, the search for command is performed using a
         default value for PATH that  is  guaranteed to find all of the standard
         utilities.  If either the -V or -v option is supplied, a description of
         command is printed.  The -v option causes a single word indicating the
         command or file name used to invoke command to  be displayed; the -V
         option produces a more verbose description.  If the -V or -v option is
         supplied, the exit status is 0 if command was found, and 1 if not.
         If neither option is supplied and an error  occurred  or command
         cannot be  found, the exit status is 127.  Otherwise, the exit status
         of the command builtin is the exit status of command.

答え4

envの引数としてPATH設定を「/usr/bin」に指定するか、適切なPATHを設定するだけです。 env -iは継承された環境を無視します。次のPATH設定を使用すると、/usr/bin/rubyを見つけることができます。

env -i PATH="/usr/bin" sh -c "which ruby" 

関連情報