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

时间:2011-07-04 09:20:20

标签: bash

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

7 个答案:

答案 0 :(得分: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; }

答案 1 :(得分:32)

您可以使用which

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

答案 2 :(得分:4)

您可以使用与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

正如评论中已经提到的那样,请避免使用which,因为它需要启动外部流程,并且可能会在some cases中向您提供错误的输出。

答案 3 :(得分:3)

TL; DR:

bash中:

function is_bin_in_path {
  builtin type -P "$1" &> /dev/null
}

is_bin_in_path的用法示例:

% is_bin_in_path ls && echo "in path" || echo "not in path"
in path

需要避免的非解决方案

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

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

示例为失败且答案为纯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

请注意,bashwhich不是内置的shell(位于zsh中):

$ PATH=/bin
$ builtin type which
which is /bin/which

This answer说为什么避免使用which

  

避免使用which。它不仅是您为执行很少工作而启动的外部过程(意味着hashtypecommand之类的内置程序要便宜得多),您还可以依靠内置程序来实际执行做您想做的事,而外部命令的效果可能随系统而异。

     

为什么要照顾?

     
      
  • 许多操作系统的which甚至没有设置退出状态 ,这意味着if which foo甚至无法在其中运行,并且会始终< / strong>报告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.

对于同时适用于{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
}

答案 4 :(得分:1)

如果命令-v foo;然后foo;否则回声&#34; foo不可用&#34; ;网络

答案 5 :(得分:0)

使用which

$ which myprogram

答案 6 :(得分:0)

我们可以使用which定义一个检查可执行文件是否存在的函数:

function is_executable() {
    which "$@" &> /dev/null
}

该函数的调用就像调用可执行文件一样。 "$@"确保which获得与该函数完全相同的参数。

&> /dev/null确保将which写入stdout或stderr的任何内容重定向到空设备(这是丢弃写入信息的特殊设备),而不是将其写入stdout或stderr通过功能。

由于该函数未明确返回返回代码,因此当它返回时,最新执行的可执行文件(在这种情况下为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),并根据命令的返回代码选择要执行的分支。命令。

或者,我们可以跳过定义函数,而直接在which语句中使用if

if which name_of_executable &> /dev/null; then
    echo "name_of_executable was found"
else
    echo "name_of_executable was NOT found"
fi

但是,我认为这会使代码的可读性稍差。