TL;DR:
在bash:
function is_bin_in_path {
builtin type -P "$1" &> /dev/null
}
is_bin_in_path的用法示例:
% is_bin_in_path ls && echo "found in path" || echo "not in path"
found in path
在zsh:
请改用whence -p 。
对于同时适用于{ba,z}sh 的版本:
# True if $1 is an executable in $PATH
# Works in both {ba,z}sh
function is_bin_in_path {
if [[ -n $ZSH_VERSION ]]; then
builtin whence -p "$1" &> /dev/null
else # bash:
builtin type -P "$1" &> /dev/null
fi
}
测试所有给定的命令在 $PATH 中都是可执行的:
# True iff all arguments are executable in $PATH
function is_bin_in_path {
if [[ -n $ZSH_VERSION ]]; then
builtin whence -p "$1" &> /dev/null
else # bash:
builtin type -P "$1" &> /dev/null
fi
[[ $? -ne 0 ]] && return 1
if [[ $# -gt 1 ]]; then
shift # We've just checked the first one
is_bin_in_path "$@"
fi
}
示例用法:
is_bin_in_path ssh-agent ssh-add && setup_ssh_agent
要避免的非解决方案
这不是一个简短的答案,因为解决方案必须正确处理:
使用普通type失败的示例(注意type 更改后的标记):
$ alias foo=ls
$ type foo && echo "in path" || echo "not in path"
foo is aliased to `ls'
in path
$ type type && echo "in path" || echo "not in path"
type is a shell builtin
in path
$ type if && echo "in path" || echo "not in path"
if is a shell keyword
in path
请注意,在bash 中,which 不是内置的 shell(它在 zsh 中):
$ PATH=/bin
$ builtin type which
which is /bin/which
This answer 说为什么要避免使用which:
避免which。它不仅是一个您启动的外部进程,只需要做很少的事情(意味着像 hash、type 或 command 这样的内置程序更便宜),您还可以依靠内置程序来实际做您想做的事情,而外部命令的效果很容易因系统而异。
为什么要关心?
- 许多操作系统都有一个
which,它甚至不设置退出状态,这意味着if which foo 甚至无法在那里工作,并且会始终报告foo 存在,即使它不存在(请注意,一些 POSIX shell 似乎也为hash 执行此操作)。
- 许多操作系统让
which 执行自定义和恶意操作,例如更改输出,甚至挂钩到包管理器。
在这种情况下,也要避免command -v
我刚刚引用的答案建议使用command -v,但这不适用于当前的“$PATH 中的可执行文件吗?”场景:它会失败,就像我上面用简单的type 说明的那样。
正确的解决方案
在bash中我们需要使用type -P:
-P force a PATH search for each NAME, even if it is an alias,
builtin, or function, and returns the name of the disk file
that would be executed
在zsh中我们需要使用whence -p:
-p Do a path search for name even if it is an alias,
reserved word, shell function or builtin.