从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这样的内建hash便宜),你也可以依靠内建函数来实际执行你想要的操作,而外部命令的影响可以从系统到系统很容易变化。

为什么在意?

  • 许多操作系统有一个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这会导致错误的程序,这与成功写入并丢弃输出(和危险!)非常不同)

    如果你的hash bang是/bin/sh那么你应该关心POSIX的说法。 typehash的退出代码不是由POSIX很好地定义的,并且在命令不存在的情况下hash可以成功退出(尚未见到type )。 command的退出状态由POSIX很好地定义,所以一个可能是最安全的使用。

    如果你的脚本使用bash ,POSIX规则就不再重要了,而且typehash变得非常安全。 type现在有一个-P来搜索PATHhash具有副作用,即命令的位置将被散列(以便下一次使用它时进行更快的查找),这通常是件好事,因为您可能检查其存在为了实际使用它。

    作为一个简单的例子,这里有一个运行gdate的函数(如果存在的话),否则为date

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

    我同意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不是。


    以下是检查命令是否存在于$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标准。 [错误报告] [标准]

    另外,如果您正在查找的命令已被定义为别名,则这将失败。

    链接地址: http://www.djcxy.com/p/1673.html

    上一篇: Check if a program exists from a Bash script

    下一篇: How do I know the script file name in a Bash script?