检查是否安装了apt-get软件包,然后安装它,如果它不在Linux上?

时间:2009-08-19 06:18:51

标签: bash shell apt-get

我正在开发一个Ubuntu系统,目前这就是我正在做的事情:

if ! which command > /dev/null; then
   echo -e "Command not found! Install? (y/n) \c"
   read
   if "$REPLY" = "y"; then
      sudo apt-get install command
   fi
fi

大多数人会这样做吗?还是有更优雅的解决方案?

25 个答案:

答案 0 :(得分:295)

要检查是否安装了packagename,请输入:

dpkg -s <packagename>

您也可以使用具有整洁输出的dpkg-query,并接受外卡。

dpkg-query -l <packagename>

要查找包含command的软件包,请尝试:

dpkg -S `which <command>`

有关详细信息,请参阅文章 Find out if package is installed in Linux dpkg cheat sheet

答案 1 :(得分:73)

为了更加明确一点,这里有一些bash脚本可以检查包并在需要时安装它。当然,您可以在发现缺少包时做其他事情,例如只需退出错误代码。

PKG_OK=$(dpkg-query -W --showformat='${Status}\n' the.package.name|grep "install ok installed")
echo Checking for somelib: $PKG_OK
if [ "" == "$PKG_OK" ]; then
  echo "No somelib. Setting up somelib."
  sudo apt-get --force-yes --yes install the.package.name
fi

如果脚本在GUI中运行(例如,它是Nautilus脚本),您可能希望将'sudo'调用替换为'gksudo'调用。

答案 2 :(得分:66)

这个单线为'nano'包返回1(已安装)或0(未安装)..

$(dpkg-query -W -f='${Status}' nano 2>/dev/null | grep -c "ok installed")

即使包不存在/也不可用。

如果未安装'nano'软件包,则以下示例将安装'nano'软件包。

if [ $(dpkg-query -W -f='${Status}' nano 2>/dev/null | grep -c "ok installed") -eq 0 ];
then
  apt-get install nano;
fi

答案 3 :(得分:11)

我提供此更新,因为Ubuntu在回答此问题时添加了“个人包存档”(PPA),并且PPA包具有不同的结果。

  1. 未安装Native Debian存储库软件包:

    ~$ dpkg-query -l apache-perl
    ~$ echo $?
    1
    
  2. 在主机上注册并安装的PPA包:

    ~$ dpkg-query -l libreoffice
    ~$ echo $?
    0
    
  3. 在主机上注册但未安装的PPA包:

    ~$ dpkg-query -l domy-ce
    ~$ echo $?
    0
    ~$ sudo apt-get remove domy-ce
    [sudo] password for user: 
    Reading package lists... Done
    Building dependency tree       
    Reading state information... Done
    Package domy-ce is not installed, so not removed
    0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
    
  4. 同时发布于:https://superuser.com/questions/427318/test-if-a-package-is-installed-in-apt/427898

答案 4 :(得分:6)

这看起来效果很好。

$ sudo dpkg-query -l | grep <some_package_name> | wc -l
  • 如果未安装,则返回0,如果已安装则返回> 0

答案 5 :(得分:6)

UpAndAdam写道:

  

但是,您不能仅仅依靠这里的返回代码来编写脚本

我的体验中,您可以依赖于dkpg的退出代码。

dpkg -s 的返回代码 0 如果已安装软件包, 1 (如果不是),那么我找到的最简单的解决方案是:

dpkg -s <pkg-name> 2>/dev/null >/dev/null || sudo apt-get -y install <pkg-name>

对我来说很好......

答案 6 :(得分:6)

dpkg -s编程用法

我喜欢dpkg -s,因为如果没有安装任何软件包,它会以状态1退出,从而很容易实现自动化:

pkgs='qemu-user pandoc'
if ! dpkg -s $pkgs >/dev/null 2>&1; then
  sudo apt-get install $pkgs
fi

另请参阅:

在Ubuntu 18.10上测试。

答案 7 :(得分:3)

灵感来自上面的克里斯

#! /bin/bash

installed() {
    return $(dpkg-query -W -f '${Status}\n' "${1}" 2>&1|awk '/ok installed/{print 0;exit}{print 1}')
}

pkgs=(libgl1-mesa-dev xorg-dev vulkan-tools libvulkan-dev vulkan-validationlayers-dev spirv-tools)
missing_pkgs=""

for pkg in ${pkgs[@]}; do
    if ! $(installed $pkg) ; then
        missing_pkgs+=" $pkg"
    fi
done

if [ ! -z "$missing_pkgs" ]; then
    cmd="sudo apt install -y $missing_pkgs"
    echo $cmd
fi

答案 8 :(得分:3)

我发现上面的所有解决方案都会产生误报,如果安装了一个软件包然后将其删除,那么安装软件包仍保留在系统上。

要复制: 安装包apt-get install curl
删除包apt-get remove curl

现在测试以上答案。

以下命令似乎解决了这个问题:
dpkg-query -W -f='${Status}\n' curl | head -n1 | awk '{print $3;}' | grep -q '^installed$'

这将产生明确的结果 已安装未安装

答案 9 :(得分:3)

我已根据Nultyi's answer确定了一个:

MISSING=$(dpkg --get-selections $PACKAGES 2>&1 | grep -v 'install$' | awk '{ print $6 }')
# Optional check here to skip bothering with apt-get if $MISSING is empty
sudo apt-get install $MISSING

基本上,来自dpkg --get-selections的错误消息比大多数其他错误消息更容易解析,因为它不包括“deinstall”等状态。它还可以同时检查多个包,只有错误代码就无法做到。

说明/示例:

$ dpkg --get-selections  python3-venv python3-dev screen build-essential jq
dpkg: no packages found matching python3-venv
dpkg: no packages found matching python3-dev
screen                                          install
build-essential                                 install
dpkg: no packages found matching jq

因此grep从列表中删除已安装的软件包,并且awk从错误消息中提取软件包名称,从而生成MISSING='python3-venv python3-dev jq',这可以简单地插入到安装命令中。

我不是盲目地发布apt-get install $PACKAGES因为正如评论中所提到的,这可能意外地升级你没有计划的包裹;对于预期稳定的自动化流程来说,这并不是一个好主意。

答案 10 :(得分:2)

$name="rsync"

[ `which $name` ] $$ echo "$name : installed" || sudo apt-get install -y $name

答案 11 :(得分:2)

这样做。 apt-get install是幂等的。

sudo apt-get install command

答案 12 :(得分:2)

使用:

apt-cache policy <package_name>

如果未安装,则会显示:

Installed: none

否则会显示:

Installed: version

答案 13 :(得分:1)

此功能已存在于Ubuntu和Debian的 command-not-found 包中。

答案 14 :(得分:1)

在本地而不是在docker中运行测试时,我有类似的要求。基本上,我只想安装找到的所有.deb文件(如果尚未安装)。

this.setState({ emails: this.state.emails.slice(0, -1) });

我想他们唯一能看到的问题是它不检查软件包的版本号,因此如果.deb文件是较新的版本,则不会覆盖当前安装的软件包。

答案 15 :(得分:1)

对于Ubuntu,apt提供了一种相当不错的方法来实现这一点。以下是Google Chrome的示例:

apt -qq list google-chrome-stable 2>/dev/null | grep -qE "(installed|upgradeable)" || apt-get install google-chrome-stable

我将错误输出重定向到null,因为apt警告不要使用它的&#34;不稳定的cli&#34;。我怀疑列表包是稳定的所以我认为可以抛弃这个警告。 -qq使得超级安静。

答案 16 :(得分:1)

apt list [packagename]

似乎是在dpkg和更旧的apt- *工具之外进行此操作的最简单方法

答案 17 :(得分:0)

已经讲了很多事情,但对我来说,最简单的方法是:

dpkg -l | grep packagename

答案 18 :(得分:0)

在Bash中:

let isEqual = true;
function deepEqual(object1, object2) {

  if (!((typeof(object1) == 'object' && typeof(object2) == 'object') || (object1 && object2))) {

    return isEqual = object1 === object2;

  } else if (typeof(object1) == 'object' && typeof(object2) == 'object') {

    if ((object1 && object2)) {

      let object1Keys = Object.keys(object1);

      let object2Keys = Object.keys(object2);
    
      if (object1Keys.length == object2Keys.length) {
        for (let index = 0; index < object1Keys.length; index++) {
          if (isEqual) {
            if (!(typeof(object1[object1Keys[index]]) == 'object' && typeof(object2[object2Keys[index]]) == 'object')) {
             isEqual = (object1[object1Keys[index]] === object2[object2Keys[index]]) && (object1Keys[index] === object2Keys[index]);
            } else {
              deepEqual(object1[object1Keys[index]], object2[object2Keys[index]]);
            }

          } else {
            return isEqual = false;
          }
        }
      }
    }

  }

  return isEqual;
}

let obj1 = {
  a: 'somestring',
  b: 42,
  c: {
    1: 'one',
    2: {
      4: 'Three'
    }
  }
};

let obj2 = {
  a: 'somestring',
  b: 42,
  c: {
    1: 'one',
    2: {
      3: 'Three'
    }
  }
};
console.log("obj1 == obj2 : ");
console.log(deepEqual(obj1, obj2));


let obj3 = {
  a: 'somestring',
  b: 42,
  c: {
    1: 'one',
    2: {
      3: 'Three'
    }
  }
};

let obj4 = {
  a: 'somestring',
  b: 42,
  c: {
    1: 'one',
    2: {
      3: 'Three'
    }
  }
};
console.log("obj3 == obj4 : ");
isEqual = true;
console.log(deepEqual(obj3, obj4));
let obj = {name: {gender: "F"}, age: 20};
isEqual = true;
console.log(deepEqual(obj, {name: {gender: "F"}, age: 20}));

请注意,您可以在PKG中使用包含多个软件包的字符串。

答案 19 :(得分:0)

which <command>
if [ $? == 1 ]; then
    <pkg-manager> -y install <command>
fi

答案 20 :(得分:0)

我使用以下方式:

which mySQL 2>&1|tee 1> /dev/null
  if [[ "$?" == 0 ]]; then
                echo -e "\e[42m MySQL already installed. Moving on...\e[0m"
        else
        sudo apt-get install -y mysql-server
                if [[ "$?" == 0 ]]; then
                        echo -e "\e[42mMy SQL installed\e[0m"
                else
                        echo -e "\e[42Installation failed\e[0m"
                fi
        fi

答案 21 :(得分:0)

如今,apt-get似乎有一个选项--no-upgrade可以满足OP的要求:

  

--no-upgrade不要升级软件包。与安装结合使用时,如果已经安装了列出的软件包,则不进行升级将阻止对其进行升级。

https://linux.die.net/man/8/apt-get的帮助页

因此您可以使用

apt-get install --no-upgrade package

package仅在未安装时安装。

答案 22 :(得分:0)

如果已安装,则显式打印0,否则仅使用awk打印1:

dpkg-query -W -f '${Status}\n' 'PKG' 2>&1|awk '/ok installed/{print 0;exit}{print 1}'

,或者如果您喜欢以其他方式选择安装1则安装0,否则:

dpkg-query -W -f '${Status}\n' 'PKG' 2>&1|awk '/ok installed/{print 1;exit}{print 0}'

**用您的包裹名称替换PKG

便捷功能:

installed() {
    return $(dpkg-query -W -f '${Status}\n' "${1}" 2>&1|awk '/ok installed/{print 0;exit}{print 1}')
}


# usage:
installed gcc && echo Yes || echo No

#or

if installed gcc; then
    echo yes
else
    echo no
fi

答案 23 :(得分:0)

这个命令是最令人难忘的:

dpkg --get-selections <package-name>

如果已安装,则打印:

  

&LT;包名称&gt;安装

否则打印

  

找不到与&lt; package-name&gt;匹配的包。

这是在Ubuntu 12.04.1(精确穿山甲)上测试的。

答案 24 :(得分:0)

我使用这个解决方案,因为我觉得它最直接。

function must_install(){ 
   return "$(apt -qq list $var --installed 2> /dev/null |wc -l)"
}

function install_if() { 
    unset install
    for var in "$@"
    do
        if $(must_install $var)
        then
            install+="${var} "
        fi
    done
    if [ -n "$install" ];
    then 
        sudo apt-get install -qy $install
    fi
}

整洁的是,must_install 返回 1 或 0,然后从调用 if 将其解释为 true 或 false,因此我们不需要任何 test 使用 [] .

install_if 接受由空格分隔的任意数量的包。

问题是,apt 不打算在脚本中使用,因此这可能随时停止工作。 8)