シェルスクリプトで外部コマンドの有無を確認したい

シェルスクリプトでは、実行環境にcurljqなどの外部コマンドが存在するかを事前にチェックし、存在しない場合はエラーメッセージを出して処理を止めたいことがある。コマンドの存在チェックにはcommandコマンドとwhichコマンドが使える。

command -v でコマンドの存在をチェックする

command -vにコマンド名を渡すと、そのコマンドが実行可能な場合はパスなどを表示し、終了ステータス0を返す。

$ command -v ls
/usr/bin/ls
$ echo $?
0

存在しないコマンドを指定した場合は何も表示せず、終了ステータスは非0になる。

$ command -v thiscommanddoesnotexist
$ echo $?
1

終了ステータスを利用すれば、if文でコマンドの存在チェックができる。

if command -v curl >/dev/null 2>&1; then
  echo "curl is installed"
else
  echo "curl is NOT installed"
fi

command -vはビルトインコマンドやシェル関数、エイリアスも判定対象に含む。

$ command -v cd
cd

$ shopt -s expand_aliases
$ alias ll="ls -la"
$ command -v ll
alias ll='ls -la'

which でコマンドの存在をチェックする

whichにコマンド名を渡すと、PATH上に該当する実行ファイルがある場合はそのパスを表示し、終了ステータス0を返す。

$ which ls
/usr/bin/ls
$ echo $?
0

存在しないコマンドを指定した場合は何も表示せず、終了ステータスは非0になる。

$ which thiscommanddoesnotexist
$ echo $?
1

whichもif文で存在チェックに使える。

if which curl >/dev/null 2>&1; then
  echo "curl is installed"
else
  echo "curl is NOT installed"
fi

whichはPATH上の実行ファイルしか探せないため、ビルトインコマンドやエイリアスは検出できない。

$ which cd
$ echo $?
1

$ alias ll="ls -la"
$ which ll
$ echo $?
1

command と which の違い

commandはシェルのビルトインコマンドである一方、which/usr/bin/whichのような外部コマンドとして提供される。

$ type command
command is a shell builtin
$ type which
which is /usr/bin/which

そのため、commandはどのシェルでも動作が保証されているが、whichはディストリビューションによって存在しなかったり、出力形式が異なったりすることがある。command -vはPOSIXで規定された機能であり、bashだけでなくdashのような/bin/shでも同様に使える。

$ sh -c 'command -v ls'
/usr/bin/ls

コマンドの存在チェックが目的であれば、ビルトインコマンドやエイリアスも判定でき、移植性の高いcommand -vを使うとよい。