为什么已安装的软件包会显示为“要移除”的状态?

在进行其他维护任务时,我注意到dpkg -l列出了大约90个状态为ri而不是预期的ii的软件包。
我仅使用aptaptitude来维护软件包,并且没有强制安装任何软件包,但我经常使用apt install --no-install-recommends ...来避免安装不需要的软件包。我还尽量仔细维护"自动安装"标志,我有2914个状态为"自动安装"的软件包(aptitude search '~i~M'),以及422个状态为"手动安装"的软件包(aptitude search '~i!~M')。 当我没有要求删除这些软件包时,软件包在dpkg -l列表中具有状态Remove + Instri)的原因是什么?看起来这些状态的软件包实际上是我想保留在系统中的软件包。例如,sudo apt dist-upgrade会在我没有注意到的情况下导致这种情况吗? (我知道我可以使用apt install --reinstall package-name重新安装这些软件包,以将状态恢复为ii。我经常清除已删除的软件包,并且aptitude search '~c'不列出任何软件包。)
(另一个存在相同问题的系统提供的额外细节:)
$ sudo apt dist-upgrade && sudo apt autoremove && dpkg -l | grep ^ri | wc -l
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Calculating upgrade... Done
The following packages have been kept back:
  virtualbox-6.0
0 upgraded, 0 newly installed, 0 to remove and 1 not upgraded.
Reading package lists... Done
Building dependency tree       
Reading state information... Done
0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded.
171

所以 dist-upgradeautoremove 都不会触及到具有 ri 状态的 171 个软件包。
具有 ri 状态的示例软件包:
$ dpkg -l ca-certificates-java
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                                            Version                      Architecture                 Description
+++-===============================================-============================-============================-===================================================================================================
ri  ca-certificates-java                            20160321ubuntu1              all                          Common CA certificates (JKS keystore)

同一套餐的附加信息如下:
$ aptitude show ca-certificates-java
Package: ca-certificates-java            
State: installed
Automatically installed: no
Multi-Arch: foreign
Version: ...

$ aptitude why ca-certificates-java 
i   default-jre-headless   Depends openjdk-8-jre-headless
iBA openjdk-8-jre-headless Depends ca-certificates-java  

$ apt-mark showhold
virtualbox-6.0

在阅读可能原因后的附加信息:
https://askubuntu.com/a/802612/50254中所解释的,可以通过运行以下命令来修复这些软件包的状态,使其与当前安装的软件包匹配(请注意,在IFS之后的换行符不是打字错误,而是该命令需要将IFS设置为单个换行符):
export IFS='
'
for i in $(dpkg -l |egrep '^[a-z]i.*' |awk '{print $2" install"}') ; do echo $i|dpkg --set-selections  ; done
unset IFS

这个问题的原因尚不清楚。"ri"状态应该意味着"dselect"(旧版Debian软件包管理器,现在已完全被"apt"取代)已经标记了要从系统中删除的软件包,如果你确实想应用这些选择状态,可以运行"apt-get dselect-upgrade"命令。请参阅"man dpkg"和"INFORMATION ABOUT PACKAGES"章节以获取更多信息。
"apt install --reinstall package-name"也可以解决问题,但它会对系统进行比最小更多的更改。

我不是百分之百确定,但我觉得带有ri标记的软件包可能是另一个被移除的软件包的依赖项,但它们没有被移除,可能是因为没有使用apt--autoremove开关。但是我不建议使用--autoremove,因为可能会移除其他需要的软件包。我希望软件包管理的这部分是完美的,但事实并非如此。我曾经因为一个应用程序将所有系统都设置为自动删除而意外导致系统崩溃。 - Terrance
那是一个好的建议,但不是原因。我补充了信息,说明dist-upgradeautoremove对这些软件包都没有任何作用。 - Mikko Rantalainen
1嗯,是的,抱歉,我对这个问题没有更多的建议了。+1,希望其他人能够遇到类似的情况并提供帮助。在我的系统上运行dpkg -l | grep -w "ri"没有任何结果,但是dpkg -l | grep -w "rc"有结果,但那是用于配置的,完全不同的情况。希望你能找到答案! - Terrance
1我对你的情况进行了更深入的研究,虽然我并没有找到确切的答案来解释这个问题的根本原因,但也许在以下链接中可以找到一些线索来解决问题:https://askubuntu.com/posts/1352232/edit,https://askubuntu.com/a/165961/231142和https://askubuntu.com/a/166254/231142。 - Terrance
@Terrance:看起来标记为ri的软件包与这个列表匹配:dpkg --get-selections | awk '$2 == "deinstall" {print $1}'。所以问题是,当我没有使用dselect时,什么过程会意外地将dselect标记为deinstall - Mikko Rantalainen
糟糕,我刚才意识到在我上面的评论中,第一个链接是我缓存中的一个链接。我的错。让我看看能否在那里找到正确的链接。它包含了一些不错的信息。 - Terrance
很遗憾,我不知道具体是什么原因导致的。我猜你可以查看/var/log/dpkg.log中的日志,或者类似于journalctl -xe的内容。我真希望我也能遇到同样的问题,这样就能有第二双眼睛来帮忙了。我还找到了另一个链接,其中提到运行--clear-selections可能会导致类似的问题。很难说是否已经运行过这个命令。https://askubuntu.com/questions/687272/revert-accidental-dpkg-clear-selections?rq=1 - Terrance
1是的,我确实也读到了关于dpkg --clear-selections的内容,但我绝对没有运行过那个命令。在阅读了它的功能后,我不会运行那个命令。我还发现deinstall在历史上被用来向dselect发送信号,表示要移除一个软件包。然而,我刚刚检查了一下,我甚至没有安装dselect,所以它不应该设置错误的标志位。这确实是一个非常有趣的问题。我目前的猜测是VirtualBox软件包执行了一些错误的命令,因为这两个系统都安装了VirtualBox,并且这个问题似乎在一般情况下非常罕见。 - Mikko Rantalainen
我还检查了journalctl,在我可用的最近1.5年日志中,它没有提到有问题的软件包。系统安装大约11个月前,所以错误一定发生在那个时候,或者造成这个问题的原因根本不会记录到journalctl中。 - Mikko Rantalainen
1个回答

免责声明:我在分发方面并不是专家,所以这只是我多次推测的结果。
序言
在一台较旧的Ubuntu机器上,我有一个状态为"ri"的软件包,即"libllvm5.0"(还有一堆其他正常的"ii"软件包,如"libllvm4.0"和"libllvm6.0")。小于等于"libllvm5.0"的软件包被标记为手动安装,但"libllvm6.0"被标记为自动安装。 所以我的猜测是,它是一个依赖项,并且通过升级或删除依赖的软件包而变得过时。
解释
逐个检查您的参数/条件:
  • 我只使用--no-install-recommends
    嗯,必要的依赖仍然会被安装,否则程序将无法运行。
  • autoremove对这些软件包没有任何影响
    嗯,有点...我很确定所有被autoremove保留的ri软件包都被标记为手动安装,尽管你从未“单独”安装过它。这是因为在初始设置之后,由于无法确定您有意安装哪些软件包,几乎没有(如果有的话)软件包被标记为自动安装。所以...一种“你手动安装了操作系统”的情况。
  • 可能是sudo apt dist-upgrade引起的吗?
    不完全是,sudo apt dist-upgrade本身不会引起这个问题,但是通过升级整个系统,更有可能导致一堆(最初安装的)软件包变得过时。
总结一下原因:我猜测这些软件包是在初始设置时安装的,因此被标记为手动安装,然后通过升级某些软件包或整个发行版而变得过时。由于它们被标记为手动安装,所以不会被autoremove命令删除。

这个解释听起来很合理。所有状态为ri的软件包,在使用aptitude show packagename查询时,状态也都是自动安装:否。然而,我期望所有手动安装的软件包始终保持在ii状态,而不是被标记为将要删除的ri状态。 - Mikko Rantalainen