
コマンドにaliasを貼っていると、whichコマンドでPATHを知りたいのにaliasが表示されてしまう。
$ which grep
grep: aliased to grep --color=auto
PATHを知りたいときは-pをつけるとPATHが表示できる。(※-pはzshのみ有効)
$ which -p grep /usr/local/opt/grep/libexec/gnubin/grep
ちなみに-aをつけるとaliasとPATHが両方表示される。(複数存在する場合、全部表示される)
$ which -a grep grep: aliased to grep --color=auto /usr/local/opt/grep/libexec/gnubin/grep /usr/bin/grep
コマンドのPATHを知るいくつかの方法
PATHを知ることができるのはwhichコマンドの他にもいくつかある。
- where(zshのみ)
$ where grep grep: aliased to grep --color=auto /usr/local/opt/grep/libexec/gnubin/grep /usr/bin/grep
- whereis
$ whereis grep /usr/bin/grep
- type
$ type -a grep grep is an alias for grep --color=auto grep is /usr/local/opt/grep/libexec/gnubin/grep grep is /usr/bin/grep
- command
$ command -vp grep
/usr/bin/grep
- whence(zshのみ)
$ whence -a grep grep --color=auto /usr/local/opt/grep/libexec/gnubin/grep /usr/bin/grep
で、結局どれを使えばいいの?
terminalでちょろっと打つぐらいなら自分が覚えてるやつを打てばいいと思う。
だが、ShellScriptにして配布等するとき、つまり汎用性を高くしたいならちょっと考えたほうがいい。
ShellScript内でよく使われる記法としては、下記のようにコマンドがインストールされているかを判定するものが挙げられる。
# lsが使用可能か判定 if which ls >/dev/null 2>&1; then echo 'Found!' else echo 'Not Found!' fi
このような使い方をする場合、とりえあずwhich、whence、whereは避けたほうがいい。
whichはギリセーフ感はあるが、-pがzshにしか無いのでできれば避けたい。また、ビルトインコマンドではなく外部コマンドなのでちょっと遅い。判定のために外部プロセスを使うのはちょっとリッチすぎるかなっていう感じ。
whenceとwhereはzshでしか動かないので却下。
となるとwhereis、type、commandになるが、whereisも脱落してもらう。
なぜならwhereisはGNU系ではコマンドだけではなく、 バイナリ, ソース, マニュアルページのファイルを探すためにも使用されるコマンドのため、思考停止でshellを読むことが難しくなる(まあパッと見たらわかると思うけど、読み手の労力は極力減らすべき)。
さて、残るはtypeとcommandだけだが、個人的にcommandはあんまり使わない。
commandはパスを知りたい場合-vpをつける必要があり、仮につけなかった場合にエラーとなってしまう。(正確には「引数で指定したコマンドを実行する」という挙動になってしまう)
# -vpをつける必要がある $ command -vp grep /usr/bin/grep # エラーになる(シンプルにgrepが実行されてしまう) $ command grep Usage: grep [OPTION]... PATTERNS [FILE]... Try 'grep --help' for more information.
whereisと同じでcommandはパスを知る以外にも用途が存在するため、あまり使いたくない。
(が、確かcommandはPOSIX互換性があるとかあった気がするし、typeと違って終了ステータスが明確になっているので、全然悪い選択肢ではなく、むしろ良い。)
以上から、汎用性も高く、書きやすく、読み手にも何をしたいのか一撃でわかるという理由からtypeを使用するべき。もしくはcommand -vp。
つまりコマンドの存在を調べるshellはこれ
コマンドの存在を何回もチェックするような場合、下のような関数を作ることが多い。
# jsっぽい関数名でhas()とかでもいいかもね exists() { type "$1" >/dev/null 2>&1 } # 使用するとき if exists ls; then echo 'Found!' else echo 'Not Found!' fi # もしくは一行で exists ls && echo 'Found!' || echo 'Not Found!'
終わり
意外に奥深いよね。 (あとhashコマンドもあった。まあいいか。)