POSIX 兼容:
command -v <the_command>
对于bash
特定环境:
hash <the_command> # For regular commands. Or...
type <the_command> # To check built-ins and keywords
避免which
。它不仅是一个外部进程,你做的很少(意味着内置像hash
, type
或command
更便宜),你也可以依靠内置实际做你想要的,而外部命令的效果可以容易因系统而异。
为何关心?
which
甚至不设置退出状态 ,这意味着if which foo
甚至不会在那里工作,并会始终报告foo
存在,即使它没有(请注意,一些 POSIX 外壳表面上做这也适用于hash
)。 which
做定制和邪恶的东西,比如修改输出,甚至挂到包管理器。 所以,不要使用which
。而是使用以下其中一个:
$ command -v foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed. Aborting."; exit 1; }
$ 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>&-
关闭 FD 2,当它尝试写入 stderr 时导致程序出错 ,这与成功写入并丢弃输出(并且危险!)非常不同
如果你的哈希爆炸是/bin/sh
那么你应该关心 POSIX 所说的。 POSIX 没有非常好地定义type
和hash
的退出代码,并且当命令不存在时, hash
看起来成功退出(还没有看到type
)。 command
的退出状态由 POSIX 很好地定义,因此可能是最安全的。
如果你的脚本使用了bash
,那么 POSIX 规则就不再重要了, type
和hash
变得非常安全。 type
现在有一个-P
来搜索PATH
, hash
有副作用,命令的位置将被哈希(为了下次你使用它时更快的查找),这通常是一件好事,因为你可能检查它是否存在于为了实际使用它。
举个简单的例子,这是一个运行gdate
的函数,如果它存在,否则为date
:
gnudate() {
if hash gdate 2>/dev/null; then
gdate "$@"
else
date "$@"
fi
}
以下是检查$PATH
是否存在命令且可执行的可移植方法:
[ -x "$(command -v foo)" ]
例:
if ! [ -x "$(command -v git)" ]; then
echo 'Error: git is not installed.' >&2
exit 1
fi
需要执行可执行检查,因为如果在$PATH
找不到具有该名称的可执行文件,bash 将返回非可执行文件。
另请注意,如果$PATH
存在与可执行文件同名的非可执行文件,则破折号将返回前者,即使后者将被执行。这是一个错误,违反了 POSIX 标准。 [ 错误报告 ] [ 标准 ]
此外,如果您要查找的命令已被定义为别名,则此操作将失败。
我同意 lhunath 不鼓励使用which
,他的解决方案对 BASH 用户完全有效。但是,为了更加便携,应使用command -v
代替:
$ command -v foo >/dev/null 2>&1 || { echo "I require foo but it's not installed. Aborting." >&2; exit 1; }
命令command
符合 POSIX 标准,请参阅此处了解其规范: http : //pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html
注意: type
是 POSIX 兼容的,但type -P
不是。