我正在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
这是大多数人会做的吗?还是有一个更优雅的解决方案?
Answers:
要检查是否packagename
已安装,请键入:
dpkg -s <packagename>
您也可以使用dpkg-query
具有整洁输出的输出,并接受通配符。
dpkg-query -l <packagename>
要查找拥有的软件包command
,请尝试:
dpkg -S `which <command>`
有关更多详细信息,请参阅文章查找软件包是否已在Linux和dpkg备忘单中安装。
if
使用。我也在寻找if
用法。
dpkg -s
并且在缺少的软件包上确实返回1,否则返回0。早期(或最新)版本有何不同?
dpkg -s
如果安装了某个软件包然后将其删除,则返回零-在这种情况下,它是Status: deinstall ok config-files
或类似的,所以是“好的”-因此对我来说,这不是一个安全的测试。 dpkg-query -l
在这种情况下,似乎也没有返回有用的结果。
为了更加明确,这里有一些bash脚本,用于检查软件包并在需要时安装它。当然,您可以在发现该软件包丢失后执行其他操作,例如简单地退出并显示错误代码。
REQUIRED_PKG="some-package"
PKG_OK=$(dpkg-query -W --showformat='${Status}\n' $REQUIRED_PKG|grep "install ok installed")
echo Checking for $REQUIRED_PKG: $PKG_OK
if [ "" = "$PKG_OK" ]; then
echo "No $REQUIRED_PKG. Setting up $REQUIRED_PKG."
sudo apt-get --yes install $REQUIRED_PKG
fi
如果脚本在GUI中运行(例如,它是Nautilus脚本),则您可能希望将“ sudo”调用替换为“ gksudo”调用。
--force-yes
似乎是个坏主意。来自手册页:“这是一个危险的选项,它将导致apt-get继续运行而不会提示是否正在做潜在有害的事情。除非在非常特殊的情况下,否则不应使用它。使用--force-yes可能会破坏您的系统!!” 在脚本中使用它会使情况变得更糟。
这种单行返回'nano'软件包的1(已安装)或0(未安装)。
$(dpkg-query -W -f='${Status}' nano 2>/dev/null | grep -c "ok installed")
即使该程序包不存在/也不可用。
如果未安装“ nano”软件包,则下面的示例将其安装。
if [ $(dpkg-query -W -f='${Status}' nano 2>/dev/null | grep -c "ok installed") -eq 0 ];
then
apt-get install nano;
fi
dpkg-query -W -f='${Status}' MYPACKAGE | grep -q -P '^install ok installed$'; echo $?
grep -P
像这样的简单正则表达式。
if ! dpkg-query -W -f='${Status}' nano | grep "ok installed"; then apt install nano; fi
-无需使用grep -c
,只需使用“ grep
dpkg -s
自动安装以编程方式使用
我很喜欢,dpkg -s
因为1
如果没有安装任何软件包,它会以状态退出,因此易于自动化:
pkgs='qemu-user pandoc'
if ! dpkg -s $pkgs >/dev/null 2>&1; then
sudo apt-get install $pkgs
fi
man dpkg
不幸的是没有记录退出状态,但是我认为依靠它应该是相当安全的:
-s, --status package-name...
Report status of specified package.
要注意的一件事是运行:
sudo apt remove <package-name>
不一定会立即删除某些程序包的所有文件(但对于其他程序包会立即删除,不确定为什么吗?),而只是将程序包标记为要删除。
在这种状态下,该软件包似乎仍然可以使用,并且其文件仍然存在,但是以后将其标记为删除。
例如,如果您运行:
pkg=certbot
sudo apt install -y "$pkg"
dpkg -s "$pkg"
echo $?
sudo apt remove -y "$pkg"
dpkg -s "$pkg"
echo $?
ls -l /usr/lib/python3/dist-packages/certbot/reporter.py
sudo apt remove --purge certbot
dpkg -s "$pkg"
echo $?
ls -l /usr/lib/python3/dist-packages/certbot/reporter.py
然后:
前两个echo $?
输出0
,只有第三个输出1
第一个的输出dpkg -s certbot
包含:
Status: deinstall ok installed
而第二个说:
Status: deinstall ok config-files
并且仅在清除后消失:
dpkg-query: package 'certbot' is not installed and no information is available
该文件/etc/logrotate.d/certbot
在系统中仍然存在apt remove
,但之后没有--purge
。
但是,/usr/lib/python3/dist-packages/certbot/reporter.py
即使在之后,该文件仍然存在--purge
。
我不明白为什么,但与hello
包第二dpkg
后apt remove
表明,他包已经被删除无--purge
:
dpkg-query: package 'hello' is not installed and no information is available
文档也非常不清楚,例如:
sudo apt dselect-upgrade
certbot
标记为时并未删除deinstall
,即使man apt-get
似乎表明:
dselect-upgrade
与传统的Debian打包前端dselect(1)结合使用。dselect-upgrade遵循dselect(1)对可用软件包的“状态”字段所做的更改,并执行实现该状态所需的操作(例如,删除旧软件包和安装新软件包)。
也可以看看:
在Ubuntu 19.10上测试。
Python apt
包
apt
在Ubuntu 18.04中有一个预安装的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
不是
sudo apt install hello; dpkg -s hello; echo $?; sudo apt remove hello; dpkg -s hello; echo $?
。您能否提供更多详细信息?
我提供了此更新,因为Ubuntu刚刚添加了其“个人软件包存档”(PPA),而这个问题已经得到回答,而PPA软件包的结果有所不同。
未安装本机Debian存储库软件包:
~$ dpkg-query -l apache-perl
~$ echo $?
1
在主机上注册并安装的PPA软件包:
~$ dpkg-query -l libreoffice
~$ echo $?
0
在主机上注册但未安装的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.
也发布在:https : //superuser.com/questions/427318/test-if-a-package-is-installed-in-apt/427898
UpAndAdam写道:
但是,您不能仅仅依靠返回码来编写脚本
以我的经验,您可以依赖dkpg的退出代码。
如果安装了软件包,则dpkg -s的返回码为0,否则为1,因此我找到的最简单的解决方案是:
dpkg -s <pkg-name> 2>/dev/null >/dev/null || sudo apt-get -y install <pkg-name>
对我来说很好...
apt-get remove <package>
,dpkg -s <package>
即使软件包为deinstalled
这似乎工作得很好。
$ sudo dpkg-query -l | grep <some_package_name> | wc -l
0
如果未安装,则返回;如果已安装,则返回一些> 0
。grep | wc -l
是反模式。要检查是否存在某些东西,您只需要grep -q
。要实际计算发生次数(在这种情况下很少有用),请使用grep -c
。
dpkg -s zip | grep -c "Package: zip"
?(使用zip作为示例包)
grep -q 'Package: zip'
返回一个退出代码,该退出代码指示是否在不打印任何内容的情况下找到了结果。
我已经根据Nultyi的答案选择了一个:
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
因为正如评论中提到的那样,这可能会意外升级您不打算使用的软件包。对于预期稳定的自动化过程而言,这并不是一个好主意。
[[ ! -z $MISSING ]] && sudo apt-get install $MISSING
我发现,如果安装了软件包然后再将其删除,但所有安装解决方案仍保留在系统上,上述所有解决方案都可能产生误报。
复制:安装软件包apt-get install curl
删除软件包apt-get remove curl
现在测试以上答案。
以下命令似乎可以解决此问题:
dpkg-query -W -f='${Status}\n' curl | head -n1 | awk '{print $3;}' | grep -q '^installed$'
这将导致最终 安装或未安装
config-files
因此,我认为| grep -q "installed"
确实需要最终输入才能获得功能退出代码状态。
| grep -q '^installed$'
看来,现在apt-get
有一个选项--no-upgrade
,只是做了OP想要的东西:
--no-upgrade
不要升级软件包。与安装结合使用时,如果已经安装了列出的软件包,则不进行升级将阻止对其进行升级。
来自https://linux.die.net/man/8/apt-get的联机帮助页
因此,您可以使用
apt-get install --no-upgrade package
并且package
只有在没有安装时才会安装。
这样就可以了。apt-get install
是幂等的。
sudo apt-get install command
apt-get install
,即使命令本身是幂等的,也不希望在已经安装了软件包的情况下对软件包执行操作。就我而言,我正在使用Ansible的raw模块在远程系统上安装一个软件包,如果我apt-get install
不加选择地运行,每次都会报告系统已更改。有条件的解决了这个问题。
软件包中的Ubuntu和Debian已经存在此功能command-not-found
。
command-not-found
是一个交互式帮助程序,不是确保您具有所需依赖项的工具。当然,声明依赖关系的正确方法是将软件打包在Debian软件包中,并Depends:
在软件包debian/control
文件中正确填写声明。
apt list [packagename]
似乎是在dpkg和较旧的apt- *工具之外执行此操作的最简单方法
在本地而不是在docker中运行测试时,我有类似的要求。基本上,我只想安装找到的所有.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文件是较新的版本,则不会覆盖当前安装的软件包。
对于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警告不要使用其“不稳定的cli”。我怀疑列表包是稳定的,所以我认为可以放弃此警告了。-qq使apt超级安静。
我使用以下方式:
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