检测可执行文件是不是在用户的 PATH [重复]
Posted
技术标签:
【中文标题】检测可执行文件是不是在用户的 PATH [重复]【英文标题】:Detect if executable file is on user's PATH [duplicate]检测可执行文件是否在用户的 PATH [重复] 【发布时间】:2011-09-28 00:12:26 【问题描述】:在 bash 脚本中,我需要确定名为 foo
的可执行文件是否在 PATH 上。
【问题讨论】:
这是 ***.com/a/677212 的副本,它有更完整的答案。 ........为什么posix中没有这个功能 现有问题不是询问可执行文件是否在用户路径上。它只是询问程序是否存在?所以,我找到了这个问题。不是“重复”。 只需使用builtin hash
即可。
【参考方案1】:
使用which
$ which myprogram
【讨论】:
which
确实很棒 =)
应该避免的,参见***.com/a/677212【参考方案2】:
你可以使用which
:
path_to_executable=$(which name_of_executable)
if [ -x "$path_to_executable" ] ; then
echo "It's here: $path_to_executable"
fi
【讨论】:
检查可执行模式标志是多余的。which
只返回可执行文件(包括脚本)
可执行文件检查的重点是确保其结果是可执行文件,而不是错误消息。
好的,我明白了。 if [ -n "$path_to_executable" ]
会更清楚(更高效)
应该避免的,见***.com/a/677212
这实际上是一个糟糕的选择。而是使用内置的替代方案。 (见特雷弗的回答)另外,这个问题与***.com/questions/592620/…【参考方案3】:
您可以使用与 POSIX 兼容的 command
内置函数:
if [ -x "$(command -v "$cmd")" ]; then
echo "$cmd is in \$PATH"
fi
需要可执行文件检查,因为command -v
检测函数和别名以及可执行文件。
在 Bash 中,您还可以将 type
与 -P
选项一起使用,这会强制进行 PATH
搜索:
if type -P "$cmd" &>/dev/null; then
echo "$cmd is in \$PATH"
fi
正如 cmets 中已经提到的,请避免使用 which
,因为它需要启动外部进程,并且可能会在 some cases 中为您提供不正确的输出。
【讨论】:
【参考方案4】:你也可以使用 Bash 内置 type -P
:
help type
cmd=ls
[[ $(type -P "$cmd") ]] && echo "$cmd is in PATH" ||
echo "$cmd is NOT in PATH" 1>&2; exit 1;
【讨论】:
可以简化:type -P "$cmd" && echo "in path" || echo "not in path"
既然他没有指定bash,最好避免bashism ***.com/a/677212
Bash 肯定是在问题中指定的:“在 bash 脚本中……”
出于好奇,为什么不直接这样做:type -P " $cmd" > /dev/null && echo "yay"
或if type -P "$cmd" > /dev/null; then
,而不是使用子shell 并将命令包装在[[ ]]
中?
@Hubro 你对浪费fork()
和测试是正确的。请参阅 this answer 以了解 -P
的解释以及在 bash
和 zsh
中均有效的更高效、可重用的函数。【参考方案5】:
如果命令 -v foo ;然后 foo ;否则回显“foo不可用”;菲
【讨论】:
这将与函数或别名中断。 This answer works, in bothbash
and zsh
你能对那个 sn-p 再解释一下吗?【参考方案6】:
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,zsh
的版本:
# True if $1 is an executable in $PATH
# Works in both ba,zsh
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.
【讨论】:
“它适用于别名和函数” - 不正确。在 Bash 中试试这个:alias foo=ls; is_bin_in_path foo && echo "in path" || echo "not in path"
.
很好,@EugeneYarmash。更新并修复。
type -P
是一种 bashism,当在无法保证 shell 是 bash 的脚本中使用时会导致问题 --- 例如,带有 $(shell)
的 makefile。
@David Given,这个问题被标记为 bash....
@TomHale 原来如此——我的错!【参考方案7】:
我们可以使用which
定义一个检查可执行文件是否存在的函数:
function is_executable()
which "$@" &> /dev/null
调用函数就像调用可执行文件一样。 "$@"
确保 which
获得与提供给函数的参数完全相同的参数。
&> /dev/null
确保 which
写入 stdout 或 stderr 的任何内容都被重定向到空设备(这是一个丢弃写入它的信息的特殊设备),而不是由函数写入 stdout 或 stderr。
由于函数没有显式返回并返回代码,当它返回时,最新执行的可执行文件的退出代码(在本例中为 which
)将是函数的返回代码。如果which
能够找到函数参数指定的可执行文件,则which
将以指示成功的代码退出,否则以指示失败的退出代码退出。 is_executable
会自动复制此行为。
然后我们可以使用该函数有条件地做某事:
if is_executable name_of_executable; then
echo "name_of_executable was found"
else
echo "name_of_executable was NOT found"
fi
这里,if
执行写在它和then
之间的命令——在我们的例子中是is_executable name_of_executable
——并根据命令的返回码选择要执行的分支。
或者,我们可以跳过定义函数,直接在if
-语句中使用which
:
if which name_of_executable &> /dev/null; then
echo "name_of_executable was found"
else
echo "name_of_executable was NOT found"
fi
但是,我认为这会降低代码的可读性。
【讨论】:
@RamGhadiyaram 当然,我可以放入一些 cmets。什么是“SO 中的低质量帖子”? 这些是左侧菜单中的第三个审核队列。如果他们认为答案信息很少且没有解释,那么它将进入审核队列。关闭。最常见的代码只有答案会去。在你的情况下是。 @RamGhadiyaram 这样好吗?以上是关于检测可执行文件是不是在用户的 PATH [重复]的主要内容,如果未能解决你的问题,请参考以下文章