如何从 Bash 脚本中检查程序是不是存在?
Posted
技术标签:
【中文标题】如何从 Bash 脚本中检查程序是不是存在?【英文标题】:How can I check if a program exists from a Bash script?如何从 Bash 脚本中检查程序是否存在? 【发布时间】:2010-10-10 04:59:30 【问题描述】:我将如何验证程序是否存在,以返回错误并退出或继续执行脚本的方式?
看起来应该很容易,但它一直困扰着我。
【问题讨论】:
什么是“程序”?它是否包括函数和别名?which
为这些返回 true。 type
不带参数将另外返回 true 用于保留字和 shell 内置函数。如果“程序”的意思是“在$PATH
中可执行”,那么请参见this answer。
同样相关的是How to 'hash -r' and refresh all shells?和When to rehash executables in $PATH with bash?
【参考方案1】:
which
命令可能很有用。 man which
如果找到可执行文件,则返回 0,如果未找到或不可执行,则返回 1:
NAME
which - locate a command
SYNOPSIS
which [-a] filename ...
DESCRIPTION
which returns the pathnames of the files which would
be executed in the current environment, had its
arguments been given as commands in a strictly
POSIX-conformant shell. It does this by searching
the PATH for executable files matching the names
of the arguments.
OPTIONS
-a print all matching pathnames of each argument
EXIT STATUS
0 if all specified commands are
found and executable
1 if one or more specified commands is nonexistent
or not executable
2 if an invalid option is specified
which
的好处在于,它可以确定可执行文件是否在运行which
的环境中可用 - 它节省了一些问题...
【讨论】:
如果您要查找任何名为 foo 的可执行文件,请使用它,但如果您想检查特定文件 /path/to/a/named/foo,请参阅我的回答。另请注意,这在某些最小系统上可能不可用,但它应该存在于任何完整的安装中...... 不要依赖其中的退出状态。许多操作系统都有一个 which 甚至没有设置除 0 以外的退出状态。【参考方案2】:尝试使用:
test -x filename
或
[ -x filename ]
来自Conditional Expressions 下的 Bash 手册页:
-x file True if file exists and is executable.
【讨论】:
这意味着您需要已经知道应用程序的完整路径。 OP 没有指定他是否要检查特定实例或任何可执行实例...我按照我阅读的方式回答了它。【参考方案3】:这取决于您是否想知道它是否存在于$PATH
变量中的某个目录中,或者您是否知道它的绝对位置。如果您想知道它是否在$PATH
变量中,请使用
if which programname >/dev/null; then
echo exists
else
echo does not exist
fi
否则使用
if [ -x /path/to/programname ]; then
echo exists
else
echo does not exist
fi
第一个示例中对/dev/null/
的重定向抑制了which
程序的输出。
【讨论】:
由于我的评论中列出的原因,您真的不应该使用“which”。【参考方案4】:如果可以的话,使用 Bash 内置函数:
which programname
...
type -P programname
【讨论】:
嗯?which
不是 Bash 内置的。
type -P 程序名是首选,见接受的答案
@RobertG 我所看到的是-P
不是POSIX。为什么首选type -P
?
我应该说“在 bash 环境中是首选”——因为我打算回答之前针对 bash 的评论。无论如何,那是几年前的事了——我想我应该再次指出标记为“已接受”的答案【参考方案5】:
回答
POSIX 兼容:
command -v <the_command>
使用示例:
if ! command -v <the_command> &> /dev/null
then
echo "<the_command> could not be found"
exit
fi
对于 Bash 特定环境:
hash <the_command> # For regular commands. Or...
type <the_command> # To check built-ins and keywords
说明
避免which
。它不仅是你启动的一个外部进程,它做的很少(意味着像 hash
、type
或 command
这样的内置程序更便宜),你还可以依靠内置程序来实际做你想做的事情,而外部命令的效果很容易因系统而异。
为什么要关心?
许多操作系统都有一个which
,它甚至不设置退出状态,这意味着if which foo
甚至无法在那里工作,并且会始终报告foo
存在,即使它不存在(请注意,一些 POSIX shell 似乎也为 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 所说的内容。 type
和 hash
的退出代码没有被 POSIX 很好地定义,当命令不存在时,hash
被视为成功退出(还没有看到 type
的这个)。 command
的退出状态由 POSIX 定义,因此使用起来可能是最安全的。
如果您的脚本使用 bash
,那么 POSIX 规则就不再重要了,type
和 hash
都可以完全安全地使用。 type
现在有一个 -P
来搜索 PATH
和 hash
的副作用是命令的位置将被散列(以便下次使用它时更快地查找),这通常是一件好事,因为您可能会检查它的存在以便实际使用它。
作为一个简单的例子,这里有一个函数,如果存在则运行gdate
,否则运行date
:
gnudate()
if hash gdate 2>/dev/null; then
gdate "$@"
else
date "$@"
fi
具有完整功能集的替代方案
您可以使用scripts-common 来满足您的需求。
要检查是否安装了某些东西,您可以这样做:
checkBin <the_command> || errorMessage "This tool requires <the_command>. Install it please, and then run this tool again."
【讨论】:
@Geert:&>/dev/null 部分隐藏了“foo”不存在时“type”发出的消息。 echo 上的 >&2 确保将错误消息发送到标准错误而不是标准输出;因为那是惯例。它们都出现在您的终端上,但标准错误绝对是错误消息和意外警告的首选输出。 -P 标志在 'sh' 中不起作用,例如 ***.com/questions/2608688/… 对于那些不熟悉 bash 中的 'advanced' i/o 重定向的人: 1)2>&-
("close output file descriptor 2", which is stderr) 有相同的结果为2> /dev/null
; 2) >&2
是1>&2
的快捷方式,您可能会认为它是“将标准输出重定向到标准错误”。请参阅Advanced Bash Scripting Guide i/o redirection page 了解更多信息。
@mikewaters ABS 看起来相当先进,描述了广泛的 bash 和非 bash CLI 功能,但它在许多方面都非常疏忽,并且没有遵循良好的做法。我在这篇评论中没有足够的空间来写一篇文章;但我可以粘贴一些 BAD 代码的随机示例:while read element ; do .. done <<< $(echo $ArrayVar[*])
、for word in $(fgrep -l $ORIGINAL *.txt)
、ls -l "$directory" | sed 1d
、for a in seq $BEGIN $END
、...许多人试图联系作者并提出改进建议,但它没有 wiki 和请求被置若罔闻。
@mikewaters 2>&-
不与 2>/dev/null
相同。前者关闭文件描述符,而后者只是将其重定向到/dev/null
。您可能看不到错误,因为程序试图在 stderr 上通知您 stderr 已关闭。【参考方案6】:
我从来没有在我可以访问的盒子上得到以前的答案。一方面,type
已经安装(做more
所做的事情)。所以需要内置指令。这个命令对我有用:
if [ `builtin type -p vim` ]; then echo "TRUE"; else echo "FALSE"; fi
【讨论】:
括号不是if
语法的一部分,只需使用if builtin type -p vim; then ...
。并且反引号是非常古老且不推荐使用的语法,$()
甚至在所有现代系统上都被 sh
支持。【参考方案7】:
对于那些感兴趣的人,如果您希望检测已安装的库,以前的答案中的任何方法都不起作用。我想你要么在物理上检查路径(可能是头文件等),要么像这样(如果你在基于 Debian 的发行版上):
dpkg --status libdb-dev | grep -q not-installed
if [ $? -eq 0 ]; then
apt-get install libdb-dev
fi
从上面可以看出,查询中的“0”答案表示未安装软件包。这是“grep”的函数 - “0”表示找到匹配项,“1”表示未找到匹配项。
【讨论】:
但是反模式cmd; if [ $? -eq 0 ]; then
应该重构为if cmd; then
这仅适用于通过dpkg
或apt
安装的库【参考方案8】:
我无法让其中一个解决方案起作用,但在稍微编辑后我想出了这个。这对我有用:
dpkg --get-selections | grep -q linux-headers-$(uname -r)
if [ $? -eq 1 ]; then
apt-get install linux-headers-$(uname -r)
fi
【讨论】:
这仅适用于基于 Debian 的系统,例如 Ubuntu。 即使对于那些系统,如果没有通过dpkg
或apt
安装命令,它也会失败。【参考方案9】:
我在我的 .bashrc 中定义了一个函数,使这更容易。
command_exists ()
type "$1" &> /dev/null ;
这是一个如何使用它的示例(来自我的.bash_profile
。)
if command_exists mvim ; then
export VISUAL="mvim --nofork"
fi
【讨论】:
&>
是做什么的?
&>
redirects both stdout and stderr 在一起。
&>
在您的 Bash 版本中可能不可用。 Marcello 的代码应该可以正常工作;它做同样的事情。
在内置和保留字上失败:例如,尝试使用单词 then
。如果您需要可执行文件存在于$PATH
中,请参阅this answer。【参考方案10】:
我同意 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。有关其规范,请参见此处:command - execute a simple command
注意:type
符合 POSIX,但type -P
不符合。
【讨论】:
同上 -exit 1;
杀死一个 xterm,如果从那里调用。
这不适用于标准 sh:你 &> 不是有效的重定向指令。
@jyavenard:问题被标记为 bash,因此更简洁的 bash 特定重定向符号 &>/dev/null
。但是,我同意你的观点,真正重要的是可移植性,我已经相应地编辑了我的答案,现在使用标准 sh redirect >/dev/null 2>&1
。
为了进一步改进这个答案,我会做两件事:1:使用“&>”来简化它,就像乔希的回答一样。 2:将 分成额外的一行,在回显之前放置一个制表符,以提高可读性
如果有人想要的话,我只是把这个衬里放到一个 bash 函数中......github.com/equant/my_bash_tools/blob/master/tarp.bash【参考方案11】:
我必须检查是否在部署 CI 服务器时安装了 Git。我最终的 Bash 脚本如下(Ubuntu 服务器):
if ! builtin type -p git &>/dev/null; then
sudo apt-get -y install git-core
fi
【讨论】:
条件比较没用,取模运行 apt-get 的启动时间,因为如果 git-core 已经安装,apt-get 将被满足并退出。 它的启动时间不容忽视,但更重要的动机是sudo
:没有条件,它总是会停止并询问密码(除非你最近做了 sudo)。顺便说一句,sudo -p "Type your password to install missing git-core: "
可能很有用,这样提示就不会突然出现。【参考方案12】:
为了模仿 Bash 的 type -P cmd
,我们可以使用符合 POSIX 的 env -i type cmd 1>/dev/null 2>&1
。
man env
# "The option '-i' causes env to completely ignore the environment it inherits."
# In other words, there are no aliases or functions to be looked up by the type command.
ls() echo 'Hello, world!';
ls
type ls
env -i type ls
cmd=ls
cmd=lsx
env -i type $cmd 1>/dev/null 2>&1 || echo "$cmd not found"; exit 1;
【讨论】:
为什么会被赞成?这实际上适用于哪些系统?type
在大多数 shell 中似乎是 builtin
,所以这不起作用,因为 env
使用 execvp
运行 command
所以 command
不能是 builtin
(并且 builtin
将始终在同一环境中运行)。这对我来说在bash
、ksh93
、zsh
、busybox [a]sh
和dash
中失败了,所有这些都提供type
作为内置shell。【参考方案13】:
要在 Bash 脚本中使用 hash
、as @lhunath suggests:
hash foo &> /dev/null
if [ $? -eq 1 ]; then
echo >&2 "foo not found."
fi
此脚本运行hash
,然后检查最新命令的退出代码(存储在$?
中的值)是否等于1
。如果hash
没有找到foo
,则退出代码将为1
。如果存在foo
,则退出代码将为0
。
&> /dev/null
从hash
重定向standard error 和standard output,使其不会出现在屏幕上,echo >&2
将消息写入标准错误。
【讨论】:
为什么不只是if hash foo &> /dev/null; then ...
?【参考方案14】:
hash-variant 有一个缺陷:例如,在命令行中你可以输入
one_folder/process
执行进程。为此,one_folder 的父文件夹必须在 $PATH 中。但是当你尝试散列这个命令时,它总是会成功:
hash one_folder/process; echo $? # will always output '0'
【讨论】:
"为此,one_folder 的父文件夹必须在$PATH
"——这是完全不准确的。试试吧。为此,one_folder 必须位于 当前目录。【参考方案15】:
checkexists()
while [ -n "$1" ]; do
[ -n "$(which "$1")" ] || echo "$1": command not found
shift
done
【讨论】:
代码很有用,但是在许多其他答案之后发布时,单词确实完成了很多,有时间试试吧:)【参考方案16】:如果您检查程序是否存在,您可能会在以后运行它。为什么不首先尝试运行它?
if foo --version >/dev/null 2>&1; then
echo Found
else
echo Not found
fi
与仅查看 PATH 目录和文件权限相比,这是一种更可靠的程序运行检查。
此外,您还可以从您的程序中获得一些有用的结果,例如它的版本。
当然,缺点是有些程序启动起来可能很繁重,有些程序没有--version
选项来立即(并成功)退出。
【讨论】:
【参考方案17】:我支持使用“命令 -v”。例如。像这样:
md=$(command -v mkdirhier) ; alias md=$md:=mkdir # bash
emacs="$(command -v emacs) -nw" || emacs=nano
alias e=$emacs
[[ -z $(command -v jed) ]] && alias jed=$emacs
【讨论】:
【参考方案18】:检查多个依赖关系并将状态告知最终用户
for cmd in latex pandoc; do
printf '%-10s' "$cmd"
if hash "$cmd" 2>/dev/null; then
echo OK
else
echo missing
fi
done
样本输出:
latex OK
pandoc missing
将10
调整为最大命令长度。它不是自动的,因为我没有看到一种非冗长的 POSIX 方式来做到这一点:
How can I align the columns of a space separated table in Bash?
检查某些apt
软件包是否与dpkg -s
一起安装,否则安装它们。
见:Check if an apt-get package is installed and then install it if it's not on Linux
之前提到过:How can I check if a program exists from a Bash script?
【讨论】:
非冗长的方法:1)摆脱宽度说明符; 2) 在命令名称的 printf 后面添加一个空格; 3) 将你的 for 循环通过管道传送到column -t
(util-linux 的一部分)。【参考方案19】:
hash foo 2>/dev/null
:适用于 Z shell (Zsh)、Bash、Dash 和 ash。
type -p foo
:它似乎适用于 Z shell、Bash 和 ash (BusyBox),但不适用于 Dash(它将 -p
解释为参数)。
command -v foo
:适用于 Z shell、Bash、Dash,但不适用于 ash (BusyBox) (-ash: command: not found
)。
另请注意,builtin
不适用于 ash 和 Dash。
【讨论】:
很棒的清单。来自哪些版本?在我的系统command -v foo
上工作 busybox sh
(BusyBox v1.22.1 (Debian 1:1.22.0-19+b3) 内置 shell (ash))。当找不到 foo 时,它会以 127 正确失败,如果找到则打印路径。【参考方案20】:
以下是检查$PATH
中是否存在命令且可执行的可移植方式:
[ -x "$(command -v foo)" ]
例子:
if ! [ -x "$(command -v git)" ]; then
echo 'Error: git is not installed.' >&2
exit 1
fi
需要执行可执行文件检查,因为如果在$PATH
中找不到具有该名称的可执行文件,bash 将返回一个不可执行文件。
另请注意,如果在$PATH
中早先存在与可执行文件同名的不可执行文件,则 dash 返回前者,即使后者会被执行。这是一个错误,违反了 POSIX 标准。 [Bug report] [Standard]
此外,如果您要查找的命令已被定义为别名,这将失败。
【讨论】:
command -v
是否会为不可执行的文件生成路径?也就是-x真的有必要吗?
@einpoklum -x
测试文件是否可执行,这就是问题所在。
@KenSharp:但这似乎是多余的,因为command
本身会测试它的可执行性——不是吗?
@einpoklum 是的,这是必要的。事实上,即使是这种解决方案也可能在一种极端情况下失效。感谢您引起我的注意。 dash、bash 和 zsh 在执行命令时都会跳过$PATH
中的不可执行文件。但是,command -v
的行为非常不一致。在破折号中,它返回$PATH
中的第一个匹配文件,无论它是否可执行。在 bash 中,它返回$PATH
中的第一个可执行文件匹配,但如果没有,它可以返回一个不可执行文件。而在 zsh 中,它永远不会返回一个不可执行的文件。
据我所知,dash
是这三个中唯一一个不符合 POSIX 的; [ -x "$(command -v COMMANDNAME)"]
将在另外两个中工作。看起来这个错误已经被报告了,但还没有得到任何回应:bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264【参考方案21】:
如果没有可用的外部type
命令(理所当然的here),我们可以使用符合POSIX 的env -i sh -c 'type cmd 1>/dev/null 2>&1'
:
# Portable version of Bash's type -P cmd (without output on stdout)
typep()
command -p env -i PATH="$PATH" sh -c '
export LC_ALL=C LANG=C
cmd="$1"
cmd="`type "$cmd" 2>/dev/null || echo "error: command $cmd not found; exiting ..." 1>&2; exit 1; `"
[ $? != 0 ] && exit 1
case "$cmd" in
*\ /*) exit 0;;
*) printf "%s\n" "error: $cmd" 1>&2; exit 1;;
esac
' _ "$1" || exit 1
# Get your standard $PATH value
#PATH="$(command -p getconf PATH)"
typep ls
typep builtin
typep ls-temp
至少在 Mac OS X v10.6.8 (Snow Leopard) 上使用 Bash 4.2.24(2) command -v ls
与移动的 /bin/ls-temp
不匹配。
【讨论】:
【参考方案22】:我的Debian 服务器设置:
当多个包包含相同的名称时,我遇到了问题。
例如apache2
。所以这是我的解决方案:
function _apt_install()
apt-get install -y $1 > /dev/null
function _apt_install_norecommends()
apt-get install -y --no-install-recommends $1 > /dev/null
function _apt_available()
if [ `apt-cache search $1 | grep -o "$1" | uniq | wc -l` = "1" ]; then
echo "Package is available : $1"
PACKAGE_INSTALL="1"
else
echo "Package $1 is NOT available for install"
echo "We can not continue without this package..."
echo "Exitting now.."
exit 0
fi
function _package_install
_apt_available $1
if [ "$PACKAGE_INSTALL" = "1" ]; then
if [ "$(dpkg-query -l $1 | tail -n1 | cut -c1-2)" = "ii" ]; then
echo "package is already_installed: $1"
else
echo "installing package : $1, please wait.."
_apt_install $1
sleep 0.5
fi
fi
function _package_install_no_recommends
_apt_available $1
if [ "$PACKAGE_INSTALL" = "1" ]; then
if [ "$(dpkg-query -l $1 | tail -n1 | cut -c1-2)" = "ii" ]; then
echo "package is already_installed: $1"
else
echo "installing package : $1, please wait.."
_apt_install_norecommends $1
sleep 0.5
fi
fi
【讨论】:
【参考方案23】:如果你们无法让这里的答案中的内容起作用并且正在拉扯头发,请尝试使用 bash -c
运行相同的命令。看看这个梦魇谵妄。这就是你运行 $(sub-command) 时真正发生的事情:
首先。它可以给你完全不同的输出。
$ command -v ls
alias ls='ls --color=auto'
$ bash -c "command -v ls"
/bin/ls
第二。它根本不会给你任何输出。
$ command -v nvm
nvm
$ bash -c "command -v nvm"
$ bash -c "nvm --help"
bash: nvm: command not found
【讨论】:
差异是由于shell的交互模式和非交互模式的不同造成的。您的 ~/.bashrc 仅在 shell 非登录和交互时才被读取。第二个看起来很奇怪,因为这一定是由于 PATH 环境变量的差异造成的,但是子 shell 继承了环境。 在我的情况下,.bashrc
前面有一个 [ -z "$PS1" ] && return
# If not running interactively, don't do anything
所以我想这就是为什么即使在非交互模式下显式采购 bashrc 也无济于事的原因。该问题可以通过调用带有ss64.com/bash/source.html 点运算符. ./script.sh
的脚本来解决,但这不是人们希望每次都输入的内容。
采购不应该采购的脚本是个坏主意。我想说的是,您的回答与所提出的问题无关,而与 Bash 及其(非)交互模式有很大关系。
如果它解释了在这些情况下发生了什么,这将是一个有用的答案附录。【参考方案24】:
我用这个,因为它很简单:
if [ $(LANG=C type example 2>/dev/null | wc -l) = 1 ]; then
echo exists;
else
echo "not exists";
fi
或
if [ $(LANG=C type example 2>/dev/null | wc -l) = 1 ]; then
echo exists
else
echo "not exists"
fi
它使用 shell 内置程序和程序的回显状态到标准输出,而不是标准错误。另一方面,如果没有找到命令,它只会将状态回显到标准错误。
【讨论】:
【参考方案25】:扩展@lhunath 和@GregV 的答案,下面是那些想要轻松地将检查放入if
语句中的人的代码:
exists()
command -v "$1" >/dev/null 2>&1
使用方法如下:
if exists bash; then
echo 'Bash exists!'
else
echo 'Your system does not have Bash'
fi
【讨论】:
愿意学习和提高必须得到奖励。 +1 这是干净和简单的。我唯一可以补充的是command
即使对于别名也能成功,这可能有点违反直觉。在交互式 shell 中检查是否存在与将其移动到脚本时会给出不同的结果。
我刚刚测试并使用shopt -u expand_aliases
忽略/隐藏别名(如另一个答案中提到的alias ls='ls -F'
)和shopt -s expand_aliases
通过command -v
解决它们。所以也许它应该在检查之前设置并在之后取消设置,尽管如果你不捕获并显式返回命令调用的输出,它可能会影响函数返回值。
为什么这在if exists conda; then
上不起作用,即使安装了anaconda 并返回:usage: conda [-h] [-V] command...
当一个人在终端中输入conda
时? (请注意,我已验证您的答案适用于 Ubuntu 20 操作系统上的 if exists bash; then
。)
@a.t. which conda
【参考方案26】:
我想说,由于悬空alias
es,没有任何可移植且 100% 可靠的方法。例如:
alias john='ls --color'
alias paul='george -F'
alias george='ls -h'
alias ringo=/
当然,只有最后一个是有问题的(没有冒犯林戈!)。但是从command -v
的角度来看,它们都是有效的alias
es。
为了拒绝像ringo
这样的悬空,我们必须解析shell 内置alias
命令的输出并递归到它们中(command -v
在这里并不优于alias
。)没有任何可移植的解决方案,即使是特定于 Bash 的解决方案也相当乏味。
请注意,这样的解决方案将无条件拒绝alias ls='ls -F'
:
test() command -v $1 | grep -qv alias
【讨论】:
好点。但是,当从 bash 脚本内部运行时,别名是不可见的。 还有一个问题,检查命令'alias'时会返回false。什么时候应该返回真。示例:测试“别名” 我刚刚测试并使用shopt -u expand_aliases
忽略/隐藏这些别名,shopt -s expand_aliases
通过command -v
显示它们。【参考方案27】:
如果你想检查一个程序是否存在并且真的是一个程序,而不是 Bash 内置命令,那么 command
、type
和 hash
不适合测试,因为它们都为内置命令返回 0 退出状态。
例如,time 程序提供了比 time 内置命令更多的功能。要检查程序是否存在,我建议使用which
,如下例所示:
# First check if the time program exists
timeProg=`which time`
if [ "$timeProg" = "" ]
then
echo "The time program does not exist on this system."
exit 1
fi
# Invoke the time program
$timeProg --quiet -o result.txt -f "%S %U + p" du -sk ~
echo "Total CPU time: `dc -f result.txt` seconds"
rm result.txt
【讨论】:
这不是痘痘。不适用于基于 debian 的现代 distors。如果不存在则返回“time not found”【参考方案28】:GIT=/usr/bin/git # STORE THE RELATIVE PATH
# GIT=$(which git) # USE THIS COMMAND TO SEARCH FOR THE RELATIVE PATH
if [[ ! -e $GIT ]]; then # CHECK IF THE FILE EXISTS
echo "PROGRAM DOES NOT EXIST."
exit 1 # EXIT THE PROGRAM IF IT DOES NOT
fi
# DO SOMETHING ...
exit 0 # EXIT THE PROGRAM IF IT DOES
【讨论】:
1) 这是一个绝对路径。 2) 您只检查程序是否存在在特定位置,而不是可调用。我可以在/usr/local/bin
中有一些东西,而你的代码会退出。【参考方案29】:
脚本
#!/bin/bash
# Commands found in the hash table are checked for existence before being
# executed and non-existence forces a normal PATH search.
shopt -s checkhash
function exists()
local mycomm=$1; shift || return 1
hash $mycomm 2>/dev/null || \
printf "\xe2\x9c\x98 [ABRT]: $mycomm: command does not exist\n"; return 1;
readonly -f exists
exists notacmd
exists bash
hash
bash -c 'printf "Fin.\n"'
结果
✘ [ABRT]: notacmd: command does not exist
hits command
0 /usr/bin/bash
Fin.
【讨论】:
【参考方案30】:这里有很多选择,但我很惊讶没有快速的单行。这是我在脚本开头使用的:
[[ "$(command -v mvn)" ]] || echo "mvn is not installed" 1>&2 ; exit 1;
[[ "$(command -v java)" ]] || echo "java is not installed" 1>&2 ; exit 1;
这是基于此处选择的答案和另一个来源。
【讨论】:
以上是关于如何从 Bash 脚本中检查程序是不是存在?的主要内容,如果未能解决你的问题,请参考以下文章