シェルでエイリアスを無視してコマンドを見つける

カテゴリ: shell

CMD="foo"
echo "$(
  unalias $CMD &> /dev/null
  command -v $CMD
)"

でいい。

詳細

POSIXにはcommandコマンドがあり、引数をコマンドとして実行してくれます。

command git config --get user.name
#> atusy

aliasを無視してくれる点が魅力ですね。

じゃあこのgitコマンドはどこにあるの?と思ったら-vオプションをつけます。

command -v git
#> /usr/bin/git

ただし、エイリアスを設定している場合はそうもいきません。

alias git=foo
command -v git
#> alias git='foo'

-pオプションをつけると、デフォルトのサーチパスからコマンドを探してくれるのでよさげですが、 bashではうまくいきません。 zshならエイリアスを無視してくれますが、ユーザーが追加したサーチパスを無視してしまいます。たとえばgitコマンドが/home/user/.local/bin/gitにあると見つかりません。

alias git=foo
command -p -v git
#> alias git='foo'

無難な解決方法はエイリアスを一時解除することでしょう。サブシェルでできます。もしもエイリアスがなくても機能するように、unalias git &> /dev/nullとしてアンエイリアスした時の結果をすべて/dev/nullにリダイレクトしてしまうといいでしょう。

alias git=foo

# サブシェルでエイリアスを一時解除してコマンドを探す
echo "$(
  unalias git &> /dev/null
  command -v git
)"
#> /usr/bin/git

ちなみにですが、bashを-cで呼びつつエイリアスも使うには

shopt -s expand_aliases

を実行しておくみたいです。この記事をR Markdownで書いたところ、エイリアスが展開されなくて困って解決策を探しました。