检测可执行文件是不是在用户的 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 的解释以及在 bashzsh 中均有效的更高效、可重用的函数。【参考方案5】:

如果命令 -v foo ;然后 foo ;否则回显“foo不可用”;菲

【讨论】:

这将与函数或别名中断。 This answer works, in both bash 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。它不仅是一个您启动的外部进程,只需要做很少的事情(意味着像 hashtypecommand 这样的内置程序更便宜),您还可以依靠内置程序来实际做您想做的事情,而外部命令的效果很容易因系统而异。

为什么要关心?

许多操作系统都有一个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 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Selenium 错误:“chromedriver”可执行文件需要在 PATH [重复]

c#中如何检测文件路径是不是存在

找到python可执行文件的路径

cx 冻结的可执行文件是不是可破解 [重复]

为 *nix 创建 Python 可执行文件 [重复]

我如何知道可执行文件是不是被增量链接?