ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

什么是“程序”?它是否包括函数和别名? which 为这些返回 true。不带参数的 type 将另外为保留字和 shell 内置返回 true。如果“程序”的意思是“在 $PATH 中可执行”,则参见 this answer
@TomHale 这取决于您使用的是 which 的哪个实现;它不是由 Bash 提供的,而是由例如 Debian 的 debianutils 提供的。

n
nishanthshanmugham

回答

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 似乎可以这也是哈希)。

许多操作系统都会做一些自定义和邪恶的事情,比如改变输出,甚至挂钩到包管理器。

所以,不要使用 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 所说的内容。 typehash 的退出代码在 POSIX 中定义得不是很好,并且当命令不存在时,可以看到 hash 成功退出(还没有看到 type 出现这种情况)。 command 的退出状态由 POSIX 很好地定义,因此使用起来可能是最安全的。

但是,如果您的脚本使用 bash,POSIX 规则就不再重要,并且 typehash 都可以完全安全地使用。 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."

您介意解释一下 &>/dev/null>&2 部分的用途吗?没有它们,这条线似乎也能正常工作。谢谢。
@Geert: &>/dev/null 部分隐藏了 'foo' 不存在时发出的消息 'type' 。 echo 上的 >&2 确保将错误消息发送到标准错误而不是标准输出;因为那是惯例。它们都出现在您的终端上,但标准错误绝对是错误消息和意外警告的首选输出。
对于那些不熟悉 bash 中的“高级”i/o 重定向的人: 1) 2>&- ("close output file descriptor 2", which is stderr)2> /dev/null 具有相同的结果; 2) >&21>&2 的快捷方式,您可以将其识别为“将标准输出重定向到标准错误”。有关详细信息,请参阅 Advanced Bash Scripting Guide i/o redirection page
n
nyuszika7h

以下是检查命令是否存在于 $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]

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


P
Peter Mortensen

我同意 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:you &> 不是有效的重定向指令。
@jyavenard:这个问题被标记为 bash,因此更简洁的 bash 特定重定向符号 &>/dev/null。但是,我同意你的看法,真正重要的是可移植性,我已经相应地编辑了我的答案,现在使用标准 sh 重定向 >/dev/null 2>&1
为了进一步改进这个答案,我会做两件事:1:使用“&>”来简化它,就像乔希的回答一样。 2:将 { } 分成额外的一行,在回显之前放置一个制表符,以提高可读性
内置词和保留字失败:例如,用词 then 试试这个。如果您需要可执行文件存在于 $PATH 中,请参阅 this answer
P
Peter Mortensen

这取决于您是否想知道它是否存在于 $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”。
J
Josh Strater

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

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

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

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

&> 有什么作用?
&> 在您的 Bash 版本中可能不可用。 Marcello 的代码应该可以正常工作;它做同样的事情。
内置词和保留字失败:例如,用词 then 试试这个。如果您需要可执行文件存在于 $PATH 中,请参阅 this answer
R
Romário

扩展@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 并在终端中输入 conda 时返回:usage: conda [-h] [-V] command...? (请注意,我已验证您的答案适用于 Ubuntu 20 操作系统上的 if exists bash; then。)
@在 which conda
@Palec 它不仅仅是别名。 command -v 还显示内置函数、函数甚至关键字,并为它们返回 0!
P
Peter Mortensen

尝试使用:

test -x filename

或者

[ -x filename ]

Conditional Expressions 下的 Bash 手册页中:

-x 文件 如果文件存在且可执行,则为真。


这意味着您需要已经知道应用程序的完整路径。
OP 没有指定他是否要检查特定实例或任何可执行实例……我以阅读的方式回答了它。
P
Peter Mortensen

要在 Bash 脚本中使用 hashas @lhunath suggests

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

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

&> /dev/nullhash 重定向 standard errorstandard output,使其不会出现在屏幕上,并且 echo >&2 将消息写入标准错误。


为什么不只是 if hash foo &> /dev/null; then ...
如果设置了 set -e,则永远不会运行 if... 部分。
P
Peter Mortensen

这里有很多选择,但我很惊讶没有快速的单线。这是我在脚本开始时使用的:

[[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1>&2 ; exit 1; }
[[ "$(command -v java)" ]] || { echo "java is not installed" 1>&2 ; exit 1; }

这是基于此处选择的答案和另一个来源。


[[ 和命令替换在这里没有用。如果未找到 mvn,只需 command -v mvn || exitexit;但是有了这个固定,这基本上只是重复了接受的答案。
A
AnthonyC

如果为 <command> 设置了 POSIX_BUILTINS 选项以进行测试,则命令 -v 可以正常工作,但如果没有,它可能会失败。 (它已经为我工作了多年,但我最近遇到了一个它不起作用的地方。)

我发现以下内容更防故障:

test -x "$(which <command>)"

因为它测试三件事:路径、存在和执行权限。


不工作。 test -x $(which ls)test -x $(which sudo) 一样返回 0,即使 ls 已安装且可运行,并且 sudo 甚至未安装在我正在运行的 docker 容器中。
@algal 我认为您需要使用引号,所以test -x "$(which <command>)"
@algal 也许 ls 是别名?如果命令有参数,我认为它不会起作用。
我不能保证这个答案,但我也推荐引用。 $ test -x $(which absent_cmd) 返回 test: too many arguments,而 test -x "$(which absent_cmd)" 已正确解析并导致退出代码 1。
@acorello,test: too many arguments 建议 which absent_cmd 返回多字错误消息。可能存在与消息同名的可执行文件。 😁 以这种方式使用 which 是个坏主意。
0
0xF

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

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

与仅查看 PATH 目录和文件权限相比,检查程序是否运行更可靠。

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

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


P
Peter Mortensen

检查多个依赖项并将状态通知最终用户

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 的一部分)。
P
Peter Mortensen

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

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

方括号不是 if 语法的一部分,只需使用 if builtin type -p vim; then ...。并且反引号是非常古老且已弃用的语法,在所有现代系统上,甚至 sh 都支持 $()
@nyuszika7h 但是这些测试可能会失败:例如 builtin type -p if 不输出任何内容并返回 0 无论 if 是否存在。
@jarno 你的论点是什么?正如您所说,它 both 不输出任何内容并返回 0,因此使用 if builtin type -p ifif [ `builtin type -p if` ] 没有区别,除了后者不必要地冗长并使用不推荐使用的语法。
@nyuszika7h 在测试名为 if 的程序是否存在时,它们都无用。
P
Peter Mortensen

hash foo 2>/dev/null:适用于 Z shell (Zsh)、Bash、Dashash

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 正确失败,如果找到则打印路径。
例如 type -p if 不起作用。
R
Richard A Quadling

我想回答同样的问题,但要在 Makefile 中运行。

install:
    @if [[ ! -x "$(shell command -v ghead)" ]]; then \
        echo 'ghead does not exist. Please install it.'; \
        exit -1; \
    fi

由于使用了 [[,因此依赖 Bash 作为 shell。
在配方中使用 $(shell ...) 几乎总是错误的。接受的答案也可以在 Makefile 中正常工作。 exit -1 没有明确定义,条件无论如何也没用。
P
Peter Mortensen

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 的可执行文件,请使用 which,但如果您想检查特定文件 /path/to/a/named/foo,请参阅我的答案。另请注意,这在某些最小系统上可能不可用,尽管它应该存在于任何完整的安装中......
不要依赖于其中的退出状态。许多操作系统都有一个 which 甚至没有设置除 0 以外的退出状态。
P
Peter Mortensen

如果可以,请使用 Bash 内置函数:

which programname

...

type -P programname

嗯? which 不是 Bash 内置。
type -P programname 是首选,请参阅接受的答案
@RobertG 我所看到的是 -P 不是 POSIX。为什么首选 type -P
我应该说“在 bash 环境中是首选”——因为我打算回答之前特定于 bash 的评论。无论如何,那是几年前的事了-我想我应该再次指出标记为“已接受”的答案
t
todd_dsm

它可能更简单,只是:

#!/usr/bin/env bash                                                                
set -x                                                                             

# if local program 'foo' returns 1 (doesn't exist) then...                                                                               
if ! type -P foo; then                                                             
    echo 'crap, no foo'                                                            
else                                                                               
    echo 'sweet, we have foo!'                                                    
fi                                                                                 

foo 更改为 vi 以触发另一个条件。


我故意让它尽可能简单。失败的唯一方法可能是错误键入程序的名称。除此之外,它应该在任何条件下工作。
为什么在执行时启用打印命令? (set -x)
set -x 是 bash 调试器。它有助于说明当人们只是复制/粘贴时发生的事情->从这样的网站执行解决方案;就这样。如果您已完成调试,请注释/删除该行。
M
Martin von Wittich

zsh,但对 zsh 脚本非常有用(例如,在编写完成脚本时):

zsh/parameter 模块提供对内部 commands 哈希表等的访问权限。从 man zshmodules

THE ZSH/PARAMETER MODULE
       The zsh/parameter module gives access to some of the internal hash  ta‐
       bles used by the shell by defining some special parameters.


[...]

       commands
              This  array gives access to the command hash table. The keys are
              the names of external commands, the values are the pathnames  of
              the  files  that would be executed when the command would be in‐
              voked. Setting a key in this array defines a new entry  in  this
              table  in the same way as with the hash builtin. Unsetting a key
              as in `unset "commands[foo]"' removes the entry  for  the  given
              key from the command hash table.

虽然它是一个可加载的模块,但它似乎是默认加载的,只要 zsh 不与 --emulate 一起使用。

例子:

martin@martin ~ % echo $commands[zsh]
/usr/bin/zsh

要快速检查某个命令是否可用,只需检查该键是否存在于哈希中:

if (( ${+commands[zsh]} ))
then
  echo "zsh is available"
fi

请注意,哈希将包含 $PATH 文件夹中的任何文件,无论它们是否可执行。为了绝对确定,您必须为此花费 stat 调用:

if (( ${+commands[zsh]} )) && [[ -x $commands[zsh] ]]
then
  echo "zsh is available"
fi

P
Peter Mortensen

对于那些感兴趣的人,如果您希望检测已安装的库,则以前的答案中的任何方法都不起作用。我想你要么在物理上检查路径(可能是头文件等),要么像这样(如果你在基于 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 安装的库
A
Adrien

这将根据位置告诉程序是否存在:

    if [ -x /usr/bin/yum ]; then
        echo "This is Centos"
    fi

是的,如果您需要在服务器、Open suse、centos、Debian 中安装软件包,我添加了此命令
P
Peter Mortensen

我会说由于悬而未决alias,没有任何便携且 100% 可靠的方法。例如:

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

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

为了拒绝像 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 显示它们。
也许这可以简单地解释为避免别名的另一个原因。
P
Peter Mortensen

如果你们无法让答案中的内容正常工作并且正在从背后拉扯头发,请尝试使用 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# If not running interactively, don't do anything 前面有一个 [ -z "$PS1" ] && return,所以我想这就是为什么即使在非交互模式下显式采购 bashrc 也无济于事的原因。该问题可以通过调用带有 ss64.com/bash/source.html 点运算符 . ./script.sh 的脚本来解决,但这不是人们希望每次都输入的内容。
采购不应该采购的脚本是个坏主意。我想说的是,您的答案与所提出的问题无关,而与 Bash 及其(非)交互模式有很大关系。
如果它解释了在这些情况下发生了什么,这将是一个有用的答案附录。
a
anycast.cw

hash-variant 有一个缺陷:例如,在命令行中,您可以输入

one_folder/process

执行流程。为此,one_folder 的父文件夹必须在 $PATH 中。但是当你尝试散列这个命令时,它总是会成功:

hash one_folder/process; echo $? # will always output '0'

“为此,one_folder 的父文件夹必须在 $PATH 中”——这是完全不准确的。试试看。为此,one_folder 必须位于 当前目录 中。
u
user2961933

我第二次使用“命令-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

P
Peter Mortensen

我必须检查是否在部署我们的 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: " 可能很有用,因此提示不会突然出现。
P
Peter Mortensen

为了模仿 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 将始终在同一环境中运行)。这对我来说在 bashksh93zshbusybox [a]shdash 中都失败了,它们都将 type 作为 shell 内置。
P
Peter Mortensen

如果没有任何可用的外部 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

至少在使用 Bash 4.2.24(2) 的 Mac OS X v10.6.8(Snow Leopard)上,command -v ls 与移动的 /bin/ls-temp 不匹配。


P
Peter Mortensen

我的 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
}

P
Peter Mortensen

如果您想检查一个程序是否存在并且确实是一个程序,而不是 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。如果不存在返回“时间未找到”
你能举一个例子 hash 告诉错误存在以给定参数的名称存在的可执行文件吗?