我正在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
大多数人都会这么做吗?还是有更优雅的解决方案?
我正在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
大多数人都会这么做吗?还是有更优雅的解决方案?
当前回答
如果您的包具有命令行接口,则可以在安装之前通过调用它的命令行工具来计算输出,从而检查包是否存在。
这里有一个叫做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;
其他回答
Ubuntu添加了它的“个人包存档”(PPA),而PPA包有不同的结果。
A native Debian repository package is not installed: ~$ dpkg-query -l apache-perl ~$ echo $? 1 A PPA package registered on the host and installed: ~$ dpkg-query -l libreoffice ~$ echo $? 0 A PPA package registered on the host, but not installed: ~$ 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.
测试APT中是否安装了软件包
这个就行了。Apt-get install是幂等的。
sudo apt-get install --no-upgrade command
建议使用以下内容的答案:
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。
既然你提到了Ubuntu,而且你想以编程的方式做到这一点(虽然也可以使用dpkg的变体,但实现起来会更复杂),这(这)肯定是可行的:
#!/bin/bash
pkgname=mutt
which $pkgname > /dev/null;isPackage=$?
if [ $isPackage != 0 ];then
echo "$pkgname not installed"
sleep 1
read -r -p "${1:-$pkgname will be installed. Are you sure? [y/N]} " response
case "$response" in
[yY][eE][sS]|[yY])
sudo apt-get install $pkgname
;;
*)
false
;;
esac
else
echo "$pkgname is installed"
sleep 1
fi
尽管为了POSIX兼容性,您可能希望使用命令-v,正如在另一个类似问题中提到的那样。
这样的话, 在上面的代码示例中,$pkgname > /dev/null应该被命令-v $pkgname替换。
dpkg-query——showformat = " $ {db: Status-Status}”
这将产生一个不太可能改变的小输出字符串,并且很容易在没有grep的情况下进行确定性比较:
pkg=hello
status="$(dpkg-query -W --showformat='${db:Status-Status}' "$pkg" 2>&1)"
if [ ! $? = 0 ] || [ ! "$status" = installed ]; then
sudo apt install $pkg
fi
美元吗?= 0检查是必要的,因为如果你以前从未安装过一个包,并且在你删除某些包(如hello)后,dpkg-query以状态1退出并输出到stderr:
dpkg-query: no packages found matching hello
而不是输出“未安装”。2>&1也会捕获错误消息,阻止它到达终端。
对于多个软件包:
pkgs='hello certbot'
install=false
for pkg in $pkgs; do
status="$(dpkg-query -W --showformat='${db:Status-Status}' "$pkg" 2>&1)"
if [ ! $? = 0 ] || [ ! "$status" = installed ]; then
install=true
break
fi
done
if "$install"; then
sudo apt install $pkgs
fi
可能的状态记录在man dpkg-query中,如下:
n = Not-installed
c = Config-files
H = Half-installed
U = Unpacked
F = Half-configured
W = Triggers-awaiting
t = Triggers-pending
i = Installed
单字母版本可以通过db: status - abbrev获得,但它们与动作和错误状态一起出现,所以您得到3个字符,需要将其删除。
所以我认为它是足够可靠的,依靠非大写的状态(Config-files vs Config-files)不改变。
DPKG -s退出状态
不幸的是,这并不是大多数用户想要的:
pkgs='qemu-user pandoc'
if ! dpkg -s $pkgs >/dev/null 2>&1; then
sudo apt-get install $pkgs
fi
因为对于某些包,例如certbot,执行:
sudo apt install certbot
sudo apt remove certbot
使certbot处于config-files状态,这意味着配置文件留在了机器中。在这种状态下,dpkg -s仍然返回0,因为仍然保留包元数据,以便能够更好地处理那些配置文件。
要实际使dpkg -s按预期返回1,需要——purge:
sudo apt remove --purge certbot
这实际上将它移动到not-installed/dpkg-query:没有找到匹配的包。
注意,只有某些包会留下配置文件。像hello这样更简单的包可以直接从安装到未安装,而不需要——purge。
在Ubuntu 20.10上测试。
Python apt包
在Ubuntu 18.04中有一个预安装的名为apt的Python 3包,它公开了一个Python apt接口!
检查包是否已安装并在未安装时安装它的脚本可以在:如何使用python-apt API安装包中看到
以下是一份副本供参考:
#!/usr/bin/env python
# aptinstall.py
import apt
import sys
pkg_name = "libjs-yui-doc"
cache = apt.cache.Cache()
cache.update()
cache.open()
pkg = cache[pkg_name]
if pkg.is_installed:
print "{pkg_name} already installed".format(pkg_name=pkg_name)
else:
pkg.mark_install()
try:
cache.commit()
except Exception, arg:
print >> sys.stderr, "Sorry, package installation failed [{err}]".format(err=str(arg))
检查可执行文件是否在PATH中
参见:如何从Bash脚本中检查程序是否存在?
另请参阅
https://askubuntu.com/questions/165951/dpkg-get-selections-shows-packages-marked-deinstall https://askubuntu.com/questions/423355/how-do-i-check-if-a-package-is-installed-on-my-server