如何检查已安装的软件包并在未安装时进行安装?

297

我正在使用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

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


9
命令名称并不总是反映它们所属的软件包名称。你的大目标是什么?为什么不尝试安装它,最坏的情况下它也不会出现问题,因为它已经安装了。 - viam0Zah
13
幸运的是,apt-get install 是幂等的,因此只需运行它而不必担心它是否已安装,这样是安全的。 - David Baucum
3
相关的,你应该使用 command -v <command> 而不是 which <command>。另请参见如何在Bash脚本中检查程序是否存在 - jww
7
不完全正确;在已安装的软件包上运行 install 命令将会升级它,如果它是过时的。通常为了安全问题保持最新状态是可取的,但如果想要稳定性则可能会令人惊讶。 - Izkata
另外值得注意的是:在现有软件包上运行安装所需的时间比检查是否已安装要长得多,例如,检查已安装软件包列表中的条目。这需要更长的时间,不是一个实际可行的解决方案。 - Peter Kionga-Kamau
1
@DavidBaucum:手动apt install已经安装的软件包也会将其标记为手动安装,如果该软件包以前被设置为自动安装,则会产生非常不希望的副作用。 - MestreLion
30个回答

0

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

# 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文件是一个更新的版本,那么它就不会覆盖当前安装的软件包。


0

建议使用类似以下内容的答案:

dpkg-query --showformat '${db:Status-Status}\n' --show $package | grep -q '^installed$'
dpkg-query --showformat '${Status}\n' --show $package | grep -q '^install ok installed$'

都是正确的。

但是如果您安装了dpkg-dev软件包,并且不仅想检查软件包是否已安装,而且还要:

  • 想知道软件包是否安装在特定版本中
  • 想要在特定架构中拥有软件包
  • 想要查看是否提供虚拟软件包

那么您可以滥用dpkg-checkbuilddeps工具来完成此任务:

dpkg-checkbuilddeps -d apt /dev/null

这将检查 apt 是否已安装。

以下将检查 apt 是否已安装至少 2.3.15 版本,grep 是否以 amd64 安装,并且虚拟包 x-window-manager 是否由某些已安装的包提供:

dpkg-checkbuilddeps -d 'apt (>= 2.3.15), grep:amd64, x-window-manager' /dev/null

dpkg-checkbuilddeps 的退出状态将告诉脚本依赖项是否已满足。由于此方法支持传递多个软件包,因此即使您想检查是否安装了多个软件包,您也只需要运行一次 dpkg-checkbuilddeps


0
apt list [packagename]

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


4
手动检查很好,但它会发出警告,说明apt不适合用于脚本编写,与apt-*工具形成对比。 - Hontvári Levente

0

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

dpkg --get-selections <package-name>

如果已安装,则打印以下内容:

<package-name> 安装

否则,它会打印以下内容:

未找到与 <package-name> 匹配的软件包。

此内容在 Ubuntu 12.04.1(Precise Pangolin)上进行了测试。

7
当使用“dpkg --get-selections <package-name>”命令时,如果未找到软件包,它不会将退出代码设置为非零。 - Lucas

0

这个代码有点基于你的,只是更加“优雅”一些。因为我很无聊。

#!/bin/bash
FOUND=("\033[38;5;10m")
NOTFOUND=("\033[38;5;9m")
PKG="${@:1}"
command ${PKG} &>/dev/null
if [[ $? != 0 ]]; then
    echo -e "${NOTFOUND}[!] ${PKG} not found [!]"
    echo -e "${NOTFOUND}[!] Would you like to install ${PKG} now ? [!]"
    read -p "[Y/N] >$ " ANSWER
    if [[ ${ANSWER} == [yY] || ${ANSWER} == [yY][eE][sS] ]]; then
        if grep -q "bian" /etc/os-release; then
            sudo apt-get install ${PKG}
        elif grep -q "arch" /etc/os-release; then
            if [[ -f /bin/yay ]] || [[ -f /bin/yaourt ]]; then
                yaourt -S ${PKG} 2>./err || yay -S ${PKG} 2>./err
            else
                sudo pacman -S ${PKG}
            fi
        elif grep -q "fedora" /etc/os-release; then
             sudo dnf install ${PKG}
        else
            echo -e "${NOTFOUND}[!] This script couldn't detect your package manager [!]"
            echo -e "${NOTFOUND}[!] Manually install it [!]"
        fi
    elif [[ ${ANSWER} == [nN] || ${ANSWER} == [nN][oO] ]]; then
        echo -e "${NOTFOUND}[!] Exiting [!]"
    fi
else
    echo -e "${FOUND}[+] ${PKG} found [+]"
fi

0
如果您的软件包具有命令行界面,您可以通过评估调用其命令行工具的输出来检查软件包是否存在,然后再安装它。
以下是一个名为helm的软件包的示例。
#!/bin/bash

# Call the command for the package silently
helm > /dev/null

# Get the exit code of the last command
command_exit_code="$(echo $?)"

# Run installation if exit code is not equal to 0
if [ "$command_exit_code" -ne "0" ]; then
    # Package does not exist: Do the package installation
else
   echo "Skipping 'helm' installation: Package already exists"
fi;

0
以下是最简单的方法来判断一个软件包是否已安装:使用which命令定位软件包是否不存在,忽略所有错误,并检查其退出状态。
which curl >/dev/null 2>&1
if [ $? -eq 0 ]; then
    echo "curl is installed."
else
    echo "curl is not installed."
fi

-1

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

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 中解释为真或假,所以我们不需要使用 [] 进行任何 test

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

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


-1
我使用以下方式:
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

所有的答案都很好,但对于像我这样的初学者来说似乎有些复杂。所以这里是适合我的解决方案。我的Linux环境是CentOS,但不能确认它是否适用于所有发行版。

PACKAGE_NAME=${PACKAGE_NAME:-node}

if ! command -v $PACKAGE_NAME > /dev/null; then
    echo "Installing $PACKAGE_NAME ..."
else
    echo "$PACKAGE_NAME already installed"
fi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接