「このpythonコマンドは、どこにインストールされたものが動いているんだろう?」「lsを打つと色が付くけど、これはaliasが効いているの?それとも本物?」——こうした「コマンドの正体」を調べるのがwhich・type・commandです。トラブルシューティングや環境確認で頻繁に使う、地味だけれど重要なコマンド群です。
この3つは似ているようで、調べられる範囲が違います。特に重要なのが、whichはaliasやシェル関数を見抜けないという点です。「whichで調べたのに何も出てこない」というのは、実はコマンドがaliasや関数だったという場合がよくあります。この記事では、実機のLinux(WSLのDebian)で3つの違いを実際に比較しながら、正しい調べ方を整理します。
which コマンドは実行ファイルのパスを表示します(PATH上を探す)。whichはalias・シェル関数・組み込みコマンドを見抜けません(空を返すことも)。type コマンドは、alias・関数・組み込み・実体ファイルをすべて区別できます。type -tで種別だけ(file/alias/function/builtin)を取得できます。command -vはPOSIX標準で、スクリプトで移植性高くコマンドの存在確認に使えます。- 「正体をちゃんと知りたいなら
type」が基本です。
コマンドが見つかる仕組み(PATH)は環境変数とPATH、aliasの仕組みはalias、シェルの設定は同記事もあわせて参考になります。
whichの基本:実行ファイルのパスを調べる
whichは、指定したコマンドがどの実行ファイルとしてPATH上に存在するかを調べ、そのパスを表示します。「このコマンドの実体はどこ?」を知る基本の方法です。
# コマンドの実行ファイルのパスを表示 which ls # /usr/bin/ls which python3 # /usr/bin/python3 # -a: PATH上の複数の該当を全部表示 which -a ls # /usr/bin/ls # /bin/ls
実機でも、which lsで/usr/bin/lsという実体のパスが表示され、which -a lsでPATH上に複数ある同名コマンドをすべて(/usr/bin/lsと/bin/ls)表示できることを確認しました。whichはPATHを順に探して「最初に見つかった実行ファイル」を返すため、「実際に動くのはどのバージョンか」を確認するのに便利です。ただし、これから見るようにwhichには大きな死角があります。
【最重要】whichはaliasや関数を見抜けない
whichの重大な制約がこれです。whichは「PATH上の実行ファイル」しか探さないため、aliasやシェル関数として定義されたコマンドを調べても、何も表示されない(正体を教えてくれない)のです。
# ll を alias として定義 alias ll='ls -la' # which で調べても…何も出てこない! which ll # ← 空(aliasは実行ファイルではないので見つけられない) # type なら正体が分かる type ll # ll is aliased to `ls -la' ← alias だと教えてくれる
実機で、llをls -laのaliasとして定義した状態でwhich llを実行すると、何も表示されませんでした(空)。whichはPATH上の実行ファイルだけを探すコマンドなので、aliasやシェル関数の存在を知らないのです。一方、type llはll is aliased to 'ls -la'と、aliasであることと中身まで正しく教えてくれました。同様に、シェル関数をwhichで調べても空になりますが、typeなら関数名 is a functionと関数の定義まで表示されます。「whichで調べたのに何も出ない」ときは、そのコマンドがalias・関数・組み込みコマンドのいずれかである可能性が高いのです。コマンドの正体を正確に知りたいなら、whichではなくtypeを使うのが正解です。
typeの基本:正体をすべて区別する
typeはbashに組み込まれたコマンドで、指定した名前がalias・シェル関数・組み込みコマンド(builtin)・実体ファイルのどれなのかを、すべて区別して教えてくれます。
# 実行ファイル
type ls
# ls is /usr/bin/ls
# 組み込みコマンド(cdやechoはbash自身の機能)
type cd
# cd is a shell builtin
type echo
# echo is a shell builtin
# 関数
type myfunc
# myfunc is a function
# myfunc () { ... } ← 関数の中身も表示される
実機でも、type lsは実行ファイルのパス、type cd・type echoはshell builtin(組み込みコマンド)、type myfuncはfunction(関数の定義も表示)と、それぞれ正しく区別できました。cdやechoが実行ファイルではなくbash自身の機能(builtin)だと分かるのもtypeならではです。コマンドの正体を1つのコマンドで完全に把握できるのがtypeの強みです。
type -tで種別だけを取得する
スクリプトの中で「このコマンドはaliasか、実体か」を判定したいときは、type -tが便利です。file・alias・function・builtinという種別の単語だけを返します。
type -t ls # file ← 実行ファイル type -t cd # builtin ← 組み込み type -t ll # alias ← alias type -t myfunc # function ← 関数 # スクリプトでの判定に使える if [ "$(type -t mycommand)" = "function" ]; then echo "関数として定義されています" fi
実機でも、type -tがls→file・cd→builtin・ll→alias・myfunc→functionと、種別を表す単語だけを返すことを確認しました。この短い出力はシェルスクリプトでの条件分岐に最適で、「このコマンドが関数なら〜、実体なら〜」といった処理を書けます。
command -v:移植性の高い存在確認
command -vは、POSIX標準で定められた方法で、コマンドの存在確認や場所の特定ができます。どのシェルでも同じように動くため、移植性が重要なスクリプトではwhichよりcommand -vが推奨されます。
# 実行ファイルならパスを表示 command -v ls # /usr/bin/ls # alias なら alias 定義を表示 command -v ll # alias ll='ls -la' # スクリプトでの定番: コマンドが存在するか確認する if command -v git > /dev/null 2>&1; then echo "git はインストールされています" else echo "git が見つかりません" fi
実機で、command -v lsが実行ファイルのパスを、command -v llがalias定義を返すことを確認しました。whichは環境によってはインストールされていないこともあり、シェルによって挙動も微妙に異なりますが、command -vはbash・sh・zshなどで共通して使えるため、スクリプトの互換性が高まります。とくに「あるコマンドがインストールされているかを確認してから処理を分岐する」という定番パターンでは、if command -v git > /dev/null 2>&1; then ...という書き方がよく使われます(出力を/dev/nullに捨てて、成否だけを見る形です)。whichを使ったインストール確認をスクリプトで見かけたら、command -vに置き換えるとより堅牢になります。
主な違い一覧
3つのコマンドの守備範囲をまとめます。
| コマンド | 特徴 |
|---|---|
which |
実行ファイルのパスのみ。alias/関数は見抜けない |
which -a |
PATH上の該当をすべて表示 |
type |
alias/関数/組み込み/実体をすべて区別 |
type -t |
種別だけ(file/alias/function/builtin) |
command -v |
POSIX標準・移植性が高い存在確認 |
よくある失敗
whichで調べたのに何も表示されない
そのコマンドがalias・関数・組み込みの可能性があります。typeで調べます。
スクリプトでwhichを使って存在確認する
whichは環境依存です。移植性の高いcommand -vを使います。
cdやechoをwhichで探して見つからない
これらは組み込みコマンド(builtin)です。typeで確認できます。
実際に動くコマンドと違うバージョンを見ている
which -aでPATH上の全該当を確認し、優先順位を調べます。
aliasの中身を確認せず本来の動作と混同する
typeでalias定義を確認し、必要なら本来のコマンドを実行します。
よくある質問
whichはPATH上の実行ファイルのパスだけを調べます。一方typeは、alias・シェル関数・組み込みコマンド・実体ファイルのどれなのかをすべて区別できます。実機でも、aliasをwhichで調べると何も表示されないのに対し、typeならaliasであることと中身まで分かることを確認しています。正体を正確に知りたいならtypeです。whichはPATH上の実行ファイルしか探さないため、これらを見つけられません。type コマンド名で調べると、正体が分かります。type lsを実行してください。ls is aliased to ...と表示されればalias、ls is /usr/bin/lsと表示されれば実体のコマンドです。多くの環境ではlsが色付けオプション付きのaliasになっています。cdはtype cdで「shell builtin(組み込み)」と分かります。command -v コマンド名 > /dev/null 2>&1を使い、その成否(終了コード)で分岐するのが定番です。command -vはPOSIX標準で移植性が高く、bash・sh・zshなどで共通して動きます。whichは環境によっては入っていないこともあるため、スクリプトではcommand -vが推奨されます。type -t コマンド名を使います。file(実行ファイル)・alias・function・builtinのいずれかの単語だけが返るため、スクリプトの条件分岐に便利です。実機でも、それぞれのコマンドで正しい種別が返ることを確認しています。まとめ
whichは実行ファイルのパスのみ。alias・関数は見抜けません。typeは、alias・関数・組み込み・実体をすべて区別できます。type -tで種別だけ(file/alias/function/builtin)を取得できます。- スクリプトの存在確認は、移植性の高い
command -vが定番です。 - 「正体を正確に知りたいなら
type」を基本に覚えておきましょう。
which・type・commandは、「このコマンドは何者か」を突き止めるための道具です。whichにはaliasや関数を見抜けない死角があることさえ知っておけば、環境調査やトラブルシューティングでつまずくことはなくなります。PATHやaliasの記事とあわせて、コマンドが「どこから来て、何として動くのか」を理解しておきましょう。
- grep(文字列検索)
- find(ファイル検索)
- sed(置換・行編集)
- awk(列抽出・集計)
- cut(列の切り出し)
- chmod(パーミッション)
- tar(圧縮・解凍)
- リダイレクトとパイプ
- echo・printf(文字列出力)
- ps・kill(プロセス管理)
- 環境変数とPATH
- which・type(コマンドの正体)
- ln(シンボリックリンク)
- cp・mv・rm(コピー/移動/削除)
- touch・mkdir(ファイル/フォルダ作成)
- basename・dirname(パス分解)
- history(コマンド履歴)
- curl(HTTP通信・API)
- jq(JSON処理)
- vim(基本操作・終了方法)
- cron・crontab(定期実行)
- test・[ ](条件判定)
- read(入力の読み取り)
- date(日付・時刻)
- sort・uniq・wc(並べ替え/集計)
- xargs(一括処理)
- chown・chgrp(所有者/グループ変更)
- diff(ファイル比較)
- du・df(ディスク使用量)
- head・tail(先頭/末尾・ログ監視)
- cat・less(ファイル表示)
- alias(コマンドの別名)
- nohup(SSH切断対策)
- tmux(セッション管理)
- よく使うコマンドまとめ
- cd(ディレクトリ移動)

