关于bash:检查是否安装了apt-get包,然后如果它不在Linux上安装它?

Check if an apt-get package is installed and then install it if it's not on Linux?

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

1
2
3
4
5
6
7
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

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


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

1
dpkg -s <packagename>

你也可以使用输出更整齐的dpkg-query,也可以接受外卡。

1
dpkg-query -l <packagename>

要找到拥有command的软件包,请尝试:

1
dpkg -S `which <command>`

有关进一步的详细信息,请参阅文章了解Linux和DPKG技术手册中是否安装了软件包。


更明确一点,这里有一些bash脚本,用于检查包并在需要时安装它。当然,您可以在发现包丢失时执行其他操作,例如只使用错误代码退出。

1
2
3
4
5
6
7
PKG_OK=$(dpkg-query -W --showformat='${Status}
'
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"调用。


此一行程序返回"nano"包的1(已安装)或0(未安装)。

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

即使包不存在/不可用。

下面的示例安装"nano"软件包(如果未安装)。

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


我提供这个更新是因为Ubuntu在回答这个问题时添加了它的"个人软件包存档"(ppa),而ppa软件包有不同的结果。

  • 未安装本机Debian存储库包:

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ~$ 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.
  • 也发布在:https://superuser.com/questions/427318/test-if-a-package-is-installed-in-apt/427898


    dpkg -s程序化使用

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

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

    参见:

    • https://askubuntu.com/questions/423355/how-do-i-check-if-a-package-is-installed-on-my-server

    在Ubuntu 18.10上测试。


    这似乎很管用。

    1
    $ sudo dpkg-query -l | grep <some_package_name> | wc -l
    • 如果没有安装,则返回0,如果安装,则返回一些数字> 0


    乌班达姆写道:

    However you can't simply rely on return codes here for scripting

    根据我的经验,你可以依靠DKPG的出口代码。

    dpkg-s的返回码是0,如果安装了包,返回码是1,所以我找到的最简单的解决方案是:

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

    对我来说很好…


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

    复制:安装apt-get install curl包拆下apt-get remove curl

    现在测试以上答案。

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

    这将导致是否已安装


    我已经根据努尔蒂的回答决定了一个问题:

    1
    2
    3
    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"这样的状态。它还可以同时检查多个包,这是您不能只使用错误代码来完成的。

    说明/示例:

    1
    2
    3
    4
    5
    6
    $ 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,因为正如评论中提到的,这可能会意外地升级您没有计划的包;对于预期稳定的自动化过程来说,这不是一个好主意。


    1
    2
    3
    $name="rsync"

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


    这就行了。apt-get install是等幂的。

    1
    sudo apt-get install command


    用途:

    1
    apt-cache policy <package_name>

    如果未安装,将显示:

    1
    Installed: none

    否则将显示:

    1
    Installed: version

    1
    apt list [packagename]

    似乎是除dpkg和旧的apt-*工具之外最简单的方法。


    对于Ubuntu来说,apt提供了一种相当不错的方法。下面是Google Chrome的一个例子:

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

    我将错误输出重定向为空,因为APT警告不要使用它的"不稳定的CLI"。我怀疑列表包是稳定的,所以我认为可以扔掉这个警告。QQ让APT超级安静。


    在本地运行测试时,我有一个类似的要求,而不是在Docker中。基本上,我只想安装任何尚未安装的.deb文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # If there are .deb files in the folder, then install them
    if [ `ls -1 *.deb 2> /dev/null | wc -l` -gt 0 ]; then
      for file in *.deb; do
        # Only install if not already installed (non-zero exit code)
        dpkg -I ${file} | grep Package: | sed -r 's/ Package:\s+(.*)/\1/g' | xargs dpkg -s
        if [ $? != 0 ]; then
            dpkg -i ${file}
        fi;
      done;
    else
      err"No .deb files found in '$PWD'"
    fi

    我想我能看到的唯一问题是它没有检查包的版本号,所以如果.deb文件是一个较新的版本,那么它不会覆盖当前安装的包。


    这个特性已经存在于Ubuntu和Debian中,在command-not-found包中。


    我使用以下方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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

    这个命令最令人难忘:

    1
    dpkg --get-selections <package-name>

    如果已安装,则打印:

    install

    否则它会打印

    No packages found matching .

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


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

    1
    dpkg -l | grep packagename


    在巴什:

    1
    2
    PKG="emacs"
    dpkg-query -l $PKG > /dev/null || sudo apt install $PKG

    注意,在pkg中可以有一个包含多个包的字符串。


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