检测可执行文件是否在用户的PATH上

Dón*_*nal 32 bash

在bash脚本中,我需要确定命名的可执行文件foo是否在PATH上.

小智 35

你也可以使用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; }
Run Code Online (Sandbox Code Playgroud)

  • 在问题中肯定指出了Bash:"在bash脚本......" (2认同)
  • 出于好奇,为什么不这样做:`type -P"$ cmd">/dev/null && echo"yay"`或`if type -P"$ cmd">/dev/null; 那么`而不是使用子shell并将命令包装在`[[]]中? (2认同)

Mic*_*yan 33

你可以使用which:

 path_to_executable=$(which name_of_executable)
 if [ -x "$path_to_executable" ] ; then
    echo "It's here: $path_to_executable"
 fi
Run Code Online (Sandbox Code Playgroud)

  • 这实际上是一个**坏**的选择.而是使用内置替代方案.(参见trevor的回答)此外,这个问题与http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script重复. (13认同)
  • 这应该避免,请参阅http://stackoverflow.com/a/677212 (8认同)
  • 检查可执行模式标志是多余的.`which`只返回可执行文件(包括脚本) (7认同)

Eug*_*ash 9

您可以使用与commandPOSIX 兼容的内置函数:

if [ -x "$(command -v "$cmd")" ]; then
    echo "$cmd is in \$PATH"
fi
Run Code Online (Sandbox Code Playgroud)

可执行检查是必需的,因为command -v检测函数和别名以及可执行文件。

在 Bash 中,您还可以使用强制搜索type-P选项PATH

if type -P "$cmd" &>/dev/null; then
    echo "$cmd is in \$PATH"
fi
Run Code Online (Sandbox Code Playgroud)

正如评论中已经提到的,避免,which因为它需要启动外部进程,并且在某些情况下可能会给您不正确的输出。


Tom*_*ale 6

TL; DR:

bash

function is_bin_in_path {
  builtin type -P "$1" &> /dev/null
}
Run Code Online (Sandbox Code Playgroud)

示例用法is_bin_in_path

function is_bin_in_path {
  builtin type -P "$1" &> /dev/null
}
Run Code Online (Sandbox Code Playgroud)

zsh

使用whence -p代替。


对于在两种情况下均可使用的版本{ba,z}sh

% is_bin_in_path ls && echo "in path" || echo "not in path"
in path
Run Code Online (Sandbox Code Playgroud)

避免的非解决方案

这不是一个简短的答案,因为解决方案必须正确处理:

  • 功能
  • 别名
  • 内置命令
  • 保留字

这例子不能用普通type(注意后令牌type变化):

# 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
}
Run Code Online (Sandbox Code Playgroud)

需要注意的是在bashwhich不是一个shell内建(它是zsh):

$ 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
Run Code Online (Sandbox Code Playgroud)

这个答案说明了为什么要避免使用which

避免which。它不仅是您为了执行很少工作而启动的外部过程(意味着诸如的内建插件hashtype还是command便宜得多),还可以依靠内建插件实际执行所需的操作,而外部命令的效果很容易因系统之间。

为什么要在意呢?

  • 许多操作系统有which甚至不设置退出状态,这意味着if which foo甚至不会在那里工作,并会始终报告foo存在,即使它没有(注意,一些POSIX炮弹似乎对这样做hash太)。
  • 许多操作系统会which做一些自定义和邪恶的事情,例如更改输出甚至挂接到包管理器。

在这种情况下,也请避免 command -v

我刚刚引用的答案建议使用command -v,但这不适用于当前的“可执行文件是否在$PATH?”中。场景:它将完全按照我上面简单说明的方式失败type


正确的解决方案

bash我们需要使用type -P

$ PATH=/bin
$ builtin type which
which is /bin/which
Run Code Online (Sandbox Code Playgroud)

zsh我们需要使用whence -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
Run Code Online (Sandbox Code Playgroud)