如何从 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。它不仅是你启动的一个外部进程,它做的很少(意味着像 hashtypecommand 这样的内置程序更便宜),你还可以依靠内置程序来实际做你想做的事情,而外部命令的效果很容易因系统而异。

为什么要关心?

许多操作系统都有一个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&gt;&amp;-2&gt;/dev/null 相同,但更短 - 这是不正确的2&gt;&amp;- 关闭 FD 2 会导致 错误 在程序尝试写入 stderr 时,这与成功写入并丢弃输出非常不同(而且很危险!))

如果您的哈希爆炸是/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

具有完整功能集的替代方案

您可以使用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&gt;&amp;- ("close output file descriptor 2", which is stderr) 有相同的结果为2&gt; /dev/null; 2) &gt;&amp;21&gt;&amp;2 的快捷方式,您可能会认为它是“将标准输出重定向到标准错误”。请参阅Advanced Bash Scripting Guide i/o redirection page 了解更多信息。 @mikewaters ABS 看起来相当先进,描述了广泛的 bash 和非 bash CLI 功能,但它在许多方面都非常疏忽,并且没有遵循良好的做法。我在这篇评论中没有足够的空间来写一篇文章;但我可以粘贴一些 BAD 代码的随机示例:while read element ; do .. done &lt;&lt;&lt; $(echo $ArrayVar[*])for word in $(fgrep -l $ORIGINAL *.txt)ls -l "$directory" | sed 1d 、for a in seq $BEGIN $END、...许多人试图联系作者并提出改进建议,但它没有 wiki 和请求被置若罔闻。 @mikewaters 2&gt;&amp;- 2&gt;/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 这仅适用于通过dpkgapt 安装的库【参考方案8】:

我无法让其中一个解决方案起作用,但在稍微编辑后我想出了这个。这对我有用:

dpkg --get-selections | grep -q linux-headers-$(uname -r)

if [ $? -eq 1 ]; then
        apt-get install linux-headers-$(uname -r)
fi

【讨论】:

这仅适用于基于 Debian 的系统,例如 Ubuntu。 即使对于那些系统,如果没有通过dpkgapt 安装命令,它也会失败。【参考方案9】:

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

command_exists () 
    type "$1" &> /dev/null ;

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

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

【讨论】:

&amp;&gt; 是做什么的? &amp;&gt; redirects both stdout and stderr 在一起。 &amp;&gt; 在您的 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 特定重定向符号 &amp;&gt;/dev/null。但是,我同意你的观点,真正重要的是可移植性,我已经相应地编辑了我的答案,现在使用标准 sh redirect &gt;/dev/null 2&gt;&amp;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&gt;/dev/null 2&gt;&amp;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 将始终在同一环境中运行)。这对我来说在bashksh93zshbusybox [a]shdash 中失败了,所有这些都提供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

&amp;&gt; /dev/nullhash 重定向standard error 和standard output,使其不会出现在屏幕上,echo &gt;&amp;2 将消息写入标准错误。

【讨论】:

为什么不只是if hash foo &amp;&gt; /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&gt;/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&gt;/dev/null 2&gt;&amp;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" ] &amp;&amp; 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】:

我想说,由于悬空aliases,没有任何可移植且 100% 可靠的方法。例如:

alias john='ls --color'
alias paul='george -F'
alias george='ls -h'
alias ringo=/

当然,只有最后一个是有问题的(没有冒犯林戈!)。但是从command -v的角度来看,它们都是有效的aliases。

为了拒绝像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 内置命令,那么 commandtypehash 不适合测试,因为它们都为内置命令返回 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 脚本中检查程序是不是存在?的主要内容,如果未能解决你的问题,请参考以下文章

检查 Bash shell 脚本中是不是存在输入参数

检查bash脚本中是不是存在mysql用户,出现错误

使用if else bash脚本检查变量是不是存在[重复]

如何检查是不是在 bash 脚本中以 root 身份运行

Bash,...检查是不是安装了程序,使用 bash 脚本 [重复]

如何检查本地是不是存在带有特定标签的 Docker 镜像?