原文出处:

http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script


不要使用which,因为相对于hash、type、command等内置命令,它不仅是一个功能不强大的外置命令。而且要依赖内置命令才能实现你的需求,同时在各个系统上的作用也有不同之处。


为啥要在意这些细节呢?

  • 很多linux发行版上的which执行完后甚至没有返回码,这就意味着在上面执行完"if which foo"就不会奏效,即使"foo"命令 不存在,系统也会报告存在,这样明显是适得其反。(部分POSIX风格的shell对hash命令也会有类似情况)

  • 很多linux发行版上的which会做一些邪恶的事情,比如改变输出结果甚至会接入到包管理器中。



因此,不要使用which,建议使用以下命令:

$ command -v foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed.  Aborting."; e
$ type foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1;
$ hash foo 2>/dev/null || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1; }

(旁注:一些人认为“2>&-”和“2>/dev/null”等同,这种想法是不对的。当它写入到标准错误输出时,“2>&-”会关闭掉命令执行出错时产生的文件描述符“2”,这与“2>/dev/null”的命令执行成功后将结果定向到空设备中是完全不一样的。)


如果你的hash-bang是“/bin/sh”,那么你就需要关注一下POSIX说明。POSIX中type及hash命令的返回码定义得不是很好,hash命令貌似是命令不存在是会返回成功(type中尚未发现此现象)。POSIX中command命令的返回码定义得很好,因此command命令或许是三者中最安全的。


如果你的脚本运行环境是bash的话,POSIX中的规则就不会造成任何影响,type和hash两个均可安全使用。type可使用-P参数来查找命令所在路径,hash的话会有副作用,它会将命令所在的位置哈希一遍(为了提高下次的查询速度),这通常是一件好事,因为为了能使用上某个命令,你可能会检查它是否存在。


以下面的gnudate函数为例,如果gdate命令存在就运行之,否则运行date命令。

gnudate() {
    if hash gdate 2>/dev/null; then
        gdate "$@"
    else
        date "$@"
    fi
}

小结:

当你的shell环境是bash时,一般使用hash或type命令。

当写一个POSIX风格的脚本时,则使用"command -v"