如何从 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
How can I check if a program exists from a Bash script?
提问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
, type
or command
are 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
。它不仅是您启动的外部进程做的很少(意味着内置程序hash
,type
或者command
更便宜),您还可以依靠内置程序来实际执行您想要的操作,而外部命令的效果很容易从系统到系统。
Why care?
为什么要关心?
- Many operating systems have a
which
that doesn't even set an exit status, meaning theif which foo
won't even work there and will alwaysreport thatfoo
exists, even if it doesn't (note that some POSIX shells appear to do this forhash
too). - Many operating systems make
which
do 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/null
but 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/sh
then you should care about what POSIX says. type
and hash
's exit codes aren't terribly well defined by POSIX, and hash
is seen to exit successfully when the command doesn't exist (haven't seen this with type
yet). command
's exit status is well defined by POSIX, so that one is probably the safest to use.
如果你的哈希爆炸是/bin/sh
那么你应该关心 POSIX 说什么。type
andhash
的退出代码不是由 POSIX 很好地定义的,并且hash
当命令不存在时被视为成功退出(还没有看到这个type
)。 command
的退出状态由 POSIX 很好地定义,因此使用它可能是最安全的。
If your script uses bash
though, POSIX rules don't really matter anymore and both type
and hash
become perfectly safe to use. type
now has a -P
to search just the PATH
and hash
has 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规则真的不重要了两者type
并hash
成为完全安全的使用。type
现在-P
可以只搜索PATH
并且hash
有一个副作用是命令的位置将被散列(下次使用它时可以更快地查找),这通常是一件好事,因为您可能会检查它是否存在以便实际使用它.
As a simple example, here's a function that runs gdate
if 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 $PATH
andis 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 -v
shall 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 command
is POSIX compliant. See here for its specification: command - execute a simple command
命令command
符合 POSIX。有关其规范,请参见此处:命令 - 执行简单命令
Note: type
is POSIX compliant, but type -P
is 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 $PATH
variable or whether you know the absolute location of it. If you want to know if it is in the $PATH
variable, 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 which
program.
第/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 if
statement:
扩展@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 hash
and then checks if the exit code of the most recent command, the value stored in $?
, is equal to 1
. If hash
doesn't find foo
, the exit code will be 1
. If foo
is present, the exit code will be 0
.
此脚本运行hash
,然后检查最近命令的退出代码(存储在 中的值$?
)是否等于1
。如果hash
没有找到foo
,退出代码将为1
。如果foo
存在,退出代码将为0
。
&> /dev/null
redirects standard errorand standard outputfrom hash
so that it doesn't appear onscreen and echo >&2
writes the message to standard error.
回答by Magnus
I never did get the previous answers to work on the box I have access to. For one, type
has been installed (doing what more
does). 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 --version
option to immediately (and successfully) exit.
当然,缺点是有些程序启动起来很繁重,有些程序没有--version
立即(并成功)退出的选项。