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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/592620/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 17:58:56  来源:igfitidea点击:

How can I check if a program exists from a Bash script?

bash

提问by gregh

How would I validate that a program exists, in a way that will either return an error and exit, or continue with the script?

我将如何验证程序是否存在,以返回错误并退出或继续执行脚本的方式?

It seems like it should be easy, but it's been stumping me.

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

回答by lhunath

Answer

回答

POSIX compatible:

POSIX 兼容:

command -v <the_command>

For Bash specific environments:

对于 Bash 特定环境:

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

Explanation

解释

Avoid which. Not only is it an external process you're launching for doing very little (meaning builtins like hash, typeor commandare way cheaper), you can also rely on the builtins to actually do what you want, while the effects of external commands can easily vary from system to system.

避免which。它不仅是您启动的外部进程做的很少(意味着内置程序hashtype或者command更便宜),您还可以依靠内置程序来实际执行您想要的操作,而外部命令的效果很容易从系统到系统。

Why care?

为什么要关心?

  • Many operating systems have a whichthat doesn't even set an exit status, meaning the if which foowon't even work there and will alwaysreport that fooexists, even if it doesn't (note that some POSIX shells appear to do this for hashtoo).
  • Many operating systems make whichdo custom and evil stuff like change the output or even hook into the package manager.
  • 许多操作系统有which甚至不设置退出状态,这意味着if which foo甚至不会在那里工作,并会始终报告foo存在,即使它没有(注意,一些POSIX炮弹似乎对这样做hash太)。
  • 许多操作系统都会which做一些自定义的和邪恶的事情,比如更改输出甚至挂接到包管理器。

So, don't use which. Instead use one of these:

所以,不要使用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; }

(Minor side-note: some will suggest 2>&-is the same 2>/dev/nullbut shorter – this is untrue. 2>&-closes FD 2 which causes an errorin the program when it tries to write to stderr, which is very different from successfully writing to it and discarding the output (and dangerous!))

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

If your hash bang is /bin/shthen you should care about what POSIX says. typeand hash's exit codes aren't terribly well defined by POSIX, and hashis seen to exit successfully when the command doesn't exist (haven't seen this with typeyet). command's exit status is well defined by POSIX, so that one is probably the safest to use.

如果你的哈希爆炸是/bin/sh那么你应该关心 POSIX 说什么。typeandhash的退出代码不是由 POSIX 很好地定义的,并且hash当命令不存在时被视为成功退出(还没有看到这个type)。 command的退出状态由 POSIX 很好地定义,因此使用它可能是最安全的。

If your script uses bashthough, POSIX rules don't really matter anymore and both typeand hashbecome perfectly safe to use. typenow has a -Pto search just the PATHand hashhas the side-effect that the command's location will be hashed (for faster lookup next time you use it), which is usually a good thing since you probably check for its existence in order to actually use it.

如果你的脚本使用bash虽然POSIX规则真的不重要了两者typehash成为完全安全的使用。type现在-P可以只搜索PATH并且hash有一个副作用是命令的位置将被散列(下次使用它时可以更快地查找),这通常是一件好事,因为您可能会检查它是否存在以便实际使用它.

As a simple example, here's a function that runs gdateif it exists, otherwise date:

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

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

回答by nyuszika7h

The following is a portable way to check whether a command exists in $PATHandis executable:

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

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

Example:

例子:

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

The executable check is needed because bash returns a non-executable file if no executable file with that name is found in $PATH.

可执行文件检查是必需的,因为如果在$PATH.

Also note that if a non-executable file with the same name as the executable exists earlier in $PATH, dash returns the former, even though the latter would be executed. This is a bug and is in violation of the POSIX standard. [Bug report] [Standard]

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

In addition, this will fail if the command you are looking for has been defined as an alias.

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

回答by GregV

I agree with lhunath to discourage use of which, and his solution is perfectly valid for Bash users. However, to be more portable, command -vshall be used instead:

我同意 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 commandis POSIX compliant. See here for its specification: command - execute a simple command

命令command符合 POSIX。有关其规范,请参见此处:命令 - 执行简单命令

Note: typeis POSIX compliant, but type -Pis not.

注意:type符合 POSIX,但type -P不是。

回答by Josh Strater

I have a function defined in my .bashrc that makes this easier.

我在我的 .bashrc 中定义了一个函数,使这更容易。

command_exists () {
    type "" &> /dev/null ;
}

Here's an example of how it's used (from my .bash_profile.)

这是一个如何使用它的示例(来自我的.bash_profile.)

if command_exists mvim ; then
    export VISUAL="mvim --nofork"
fi

回答by dreamlax

It depends on whether you want to know whether it exists in one of the directories in the $PATHvariable or whether you know the absolute location of it. If you want to know if it is in the $PATHvariable, use

这取决于您是想知道它是否存在于$PATH变量中的某个目录中,或者您是否知道它的绝对位置。如果您想知道它是否在$PATH变量中,请使用

if which programname >/dev/null; then
    echo exists
else
    echo does not exist
fi

otherwise use

否则使用

if [ -x /path/to/programname ]; then
    echo exists
else
    echo does not exist
fi

The redirection to /dev/null/in the first example suppresses the output of the whichprogram.

/dev/null/一个示例中的重定向到抑制了which程序的输出。

回答by Romário

Expanding on @lhunath's and @GregV's answers, here's the code for the people who want to easily put that check inside an ifstatement:

扩展@lhunath 和@GregV 的答案,这里是那些想要轻松地将该检查放入if语句中的人的代码:

exists()
{
  command -v "" >/dev/null 2>&1
}

Here's how to use it:

以下是如何使用它:

if exists bash; then
  echo 'Bash exists!'
else
  echo 'Your system does not have Bash'
fi

回答by dmckee --- ex-moderator kitten

Try using:

尝试使用:

test -x filename

or

或者

[ -x filename ]

From the Bash manpage under Conditional Expressions:

条件表达式下的 Bash 联机帮助页:

 -x file
          True if file exists and is executable.
 -x file
          True if file exists and is executable.

回答by dcharles

To use hash, as @lhunath suggests, in a Bash script:

要使用hash如@lhunath表明,在bash脚本:

hash foo &> /dev/null
if [ $? -eq 1 ]; then
    echo >&2 "foo not found."
fi

This script runs hashand then checks if the exit code of the most recent command, the value stored in $?, is equal to 1. If hashdoesn't find foo, the exit code will be 1. If foois present, the exit code will be 0.

此脚本运行hash,然后检查最近命令的退出代码(存储在 中的值$?)是否等于1。如果hash没有找到foo,退出代码将为1。如果foo存在,退出代码将为0

&> /dev/nullredirects standard errorand standard outputfrom hashso that it doesn't appear onscreen and echo >&2writes the message to standard error.

&> /dev/null重定向标准错误标准输出hash以便它不会出现在屏幕上并将echo >&2消息写入标准错误。

回答by Magnus

I never did get the previous answers to work on the box I have access to. For one, typehas been installed (doing what moredoes). So the builtin directive is needed. This command works for me:

我从来没有得到以前的答案来处理我可以访问的盒子。一方面,type已经安装(做什么more)。所以需要内置指令。这个命令对我有用:

if [ `builtin type -p vim` ]; then echo "TRUE"; else echo "FALSE"; fi

回答by 0xF

If you check for program existence, you are probably going to run it later anyway. Why not try to run it in the first place?

如果您检查程序是否存在,那么无论如何您可能会稍后运行它。为什么不首先尝试运行它?

if foo --version >/dev/null 2>&1; then
    echo Found
else
    echo Not found
fi

It's a more trustworthy check that the program runs than merely looking at PATH directories and file permissions.

程序运行的检查比仅查看 PATH 目录和文件权限更值得信赖。

Plus you can get some useful result from your program, such as its version.

另外,您可以从程序中获得一些有用的结果,例如它的版本。

Of course the drawbacks are that some programs can be heavy to start and some don't have a --versionoption to immediately (and successfully) exit.

当然,缺点是有些程序启动起来很繁重,有些程序没有--version立即(并成功)退出的选项。