协慌网

登录 贡献 社区

如何从 Bash 脚本检查程序是否存在?

如何验证程序是否存在,以便返回错误并退出或继续使用脚本?

看起来应该很容易,但它一直在困扰我。

答案

回答

POSIX 兼容:

command -v <the_command>

对于bash特定环境:

hash <the_command> # For regular commands. Or...
type <the_command> # To check built-ins and keywords

说明

避免which 。它不仅是一个外部进程,你做的很少(意味着内置像hashtypecommand更便宜),你也可以依靠内置实际做你想要的,而外部命令的效果可以容易因系统而异。

为何关心?

  • 许多操作系统有一个which 甚至不设置退出状态 ,这意味着if which foo甚至不会在那里工作,并会始终报告foo存在,即使它没有(请注意,一些 POSIX 外壳表面上做这也适用于hash )。
  • 许多操作系统使得which做定制和邪恶的东西,比如修改输出,甚至挂到包管理器。

所以,不要使用which 。而是使用以下其中一个:

$ command -v foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1; }
$ type foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1; }
$ hash foo 2>/dev/null || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1; }

(次要注意:有些人会建议2>&-是相同的2>/dev/null但是更短 - 这是不真实的 2>&-关闭 FD 2,当它尝试写入 stderr 时导致程序出错 ,这与成功写入并丢弃输出(并且危险!)非常不同

如果你的哈希爆炸是/bin/sh那么你应该关心 POSIX 所说的。 POSIX 没有非常好地定义typehash的退出代码,并且当命令不存在时, hash看起来成功退出(还没有看到type )。 command的退出状态由 POSIX 很好地定义,因此可能是最安全的。

如果你的脚本使用了bash ,那么 POSIX 规则就不再重要了, typehash变得非常安全。 type现在有一个-P来搜索PATHhash有副作用,命令的位置将被哈希(为了下次你使用它时更快的查找),这通常是一件好事,因为你可能检查它是否存在于为了实际使用它。

举个简单的例子,这是一个运行gdate的函数,如果它存在,否则为date

gnudate() {
    if hash gdate 2>/dev/null; then
        gdate "$@"
    else
        date "$@"
    fi
}

以下是检查$PATH是否存在命令可执行的可移植方法:

[ -x "$(command -v foo)" ]

例:

if ! [ -x "$(command -v git)" ]; then
  echo 'Error: git is not installed.' >&2
  exit 1
fi

需要执行可执行检查,因为如果在$PATH找不到具有该名称的可执行文件,bash 将返回非可执行文件。

另请注意,如果$PATH存在与可执行文件同名的非可执行文件,则破折号将返回前者,即使后者将被执行。这是一个错误,违反了 POSIX 标准。 [ 错误报告 ] [ 标准 ]

此外,如果您要查找的命令已被定义为别名,则此操作将失败。

我同意 lhunath 不鼓励使用which ,他的解决方案对 BASH 用户完全有效。但是,为了更加便携,应使用command -v代替:

$ command -v foo >/dev/null 2>&1 || { echo "I require foo but it's not installed.  Aborting." >&2; exit 1; }

命令command符合 POSIX 标准,请参阅此处了解其规范: http//pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html

注意: type是 POSIX 兼容的,但type -P不是。