下载/安装软件包列表和逐个下载每个软件包之间有什么区别吗?

给定一个开发包列表(例如 pkgs="python3.5-dev python3-tk"),在运行时是否会有差异?
sudo apt-get install $pkgs 

vs.
for p in $pkgs; do sudo apt-get install $p; done

我主要是在询问与依赖关系拓扑排序相关的问题,即无论哪种方式,是否会下载和安装不同的软件包。
2个回答

是的,可以选择不同的软件包来满足依赖关系。运行一个指定安装N个软件包的命令,有时与运行N个命令,每个命令指定安装一个软件包,产生的效果可能不同,即使在每种情况下指定的实际软件包是相同的。
主要的实际差异可能是karel描述的。然而,即使所有操作都成功,由于不同的依赖关系解析,效果也可能不同。
原因如你所推测的那样:
大致上说,这是因为可能有多个替代方案可以满足一个依赖关系。
抽象解释:
假设您希望安装包a,它依赖于一个虚拟包v,而v可以通过包b或包c来满足,没有其他方式。假设b不依赖于cc不依赖于b,并且这些包都尚未安装。现在假设您运行:
sudo apt-get install a

然后APT将选择bc来满足依赖关系。它选择哪一个取决于它执行的计算,可能会受到您安装的软件包、可用的软件包、APT的版本以及配置方式的影响。但是当所有这些条件都相同时,每次都会做出相同的决策。
假设不失一般性,它选择了b。那么ab都已安装。假设您随后运行:
sudo apt-get install c

之后,abc都被安装了。也就是说,运行后安装了这三个软件包:

sudo apt-get install a
sudo apt-get install c

相反地,假设你运行的是这个命令而不是那些:
sudo apt-get install a c

然后,由于av的依赖已经被c满足,所以b没有被安装。也就是说,只有ac被安装了,而b没有作为运行的结果被安装。
sudo apt-get install a c

具体示例

您可以通过使用aptapt-get命令的-s选项来找到具体示例,该选项会模拟您的操作而不是执行它。 (只需记住,您不能仅通过apt-get -s/apt -s来完全确认它们,因为早期的apt-get -s/apt -s命令不会影响后续的命令,因为它们不会对任何东西产生影响,只是模拟而已。)

在我的Ubuntu 16.04 LTS系统上运行sudo apt-get install jedit将安装几个OpenJDK 8软件包:

ek@Io:~$ apt -s install jedit
NOTE: This is only a simulation!
      apt-get needs root privileges for real execution.
      Keep also in mind that locking is deactivated,
      so don't depend on the relevance to the real current situation!
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  ca-certificates-java default-jre default-jre-headless java-common java-wrappers openjdk-8-jre openjdk-8-jre-headless
Suggested packages:
  default-java-plugin icedtea-8-plugin fonts-wqy-zenhei fonts-indic
The following NEW packages will be installed:
  ca-certificates-java default-jre default-jre-headless java-common java-wrappers jedit openjdk-8-jre
  openjdk-8-jre-headless
0 upgraded, 8 newly installed, 0 to remove and 11 not upgraded.
Inst java-wrappers (0.1.28 Ubuntu:16.04/xenial [all])
Inst ca-certificates-java (20160321ubuntu1 Ubuntu:16.04/xenial-updates [all]) []
Inst java-common (0.56ubuntu2 Ubuntu:16.04/xenial [all]) []
Inst openjdk-8-jre-headless (8u222-b10-1ubuntu1~16.04.1 Ubuntu:16.04/xenial-updates, Ubuntu:16.04/xenial-security [amd64])
Inst default-jre-headless (2:1.8-56ubuntu2 Ubuntu:16.04/xenial [amd64])
Inst openjdk-8-jre (8u222-b10-1ubuntu1~16.04.1 Ubuntu:16.04/xenial-updates, Ubuntu:16.04/xenial-security [amd64])
Inst default-jre (2:1.8-56ubuntu2 Ubuntu:16.04/xenial [amd64])
Inst jedit (5.3.0+dfsg-1 Ubuntu:16.04/xenial [all])
Conf java-wrappers (0.1.28 Ubuntu:16.04/xenial [all])
Conf java-common (0.56ubuntu2 Ubuntu:16.04/xenial [all])
Conf ca-certificates-java (20160321ubuntu1 Ubuntu:16.04/xenial-updates [all])
Conf openjdk-8-jre-headless (8u222-b10-1ubuntu1~16.04.1 Ubuntu:16.04/xenial-updates, Ubuntu:16.04/xenial-security [amd64])
Conf default-jre-headless (2:1.8-56ubuntu2 Ubuntu:16.04/xenial [amd64])
Conf openjdk-8-jre (8u222-b10-1ubuntu1~16.04.1 Ubuntu:16.04/xenial-updates, Ubuntu:16.04/xenial-security [amd64])
Conf default-jre (2:1.8-56ubuntu2 Ubuntu:16.04/xenial [amd64])
Conf jedit (5.3.0+dfsg-1 Ubuntu:16.04/xenial [all])

如果我通过运行“sudo apt-get install jedit openjdk-9-jre”告诉APT同时安装jedit和openjdk-9-jre,那么它不会安装OpenJDK 8软件包,因为jedit对Java运行时的依赖已经被OpenJDK 9软件包满足。
ek@Io:~$ apt -s install jedit openjdk-9-jre
NOTE: This is only a simulation!
      apt-get needs root privileges for real execution.
      Keep also in mind that locking is deactivated,
      so don't depend on the relevance to the real current situation!
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  ca-certificates-java java-common java-wrappers libatk-wrapper-java libatk-wrapper-java-jni openjdk-9-jre-headless
Suggested packages:
  default-jre icedtea-8-plugin fonts-indic
The following NEW packages will be installed:
  ca-certificates-java java-common java-wrappers jedit libatk-wrapper-java libatk-wrapper-java-jni openjdk-9-jre
  openjdk-9-jre-headless
0 upgraded, 8 newly installed, 0 to remove and 11 not upgraded.
Inst java-wrappers (0.1.28 Ubuntu:16.04/xenial [all])
Inst ca-certificates-java (20160321ubuntu1 Ubuntu:16.04/xenial-updates [all]) []
Inst java-common (0.56ubuntu2 Ubuntu:16.04/xenial [all]) []
Inst openjdk-9-jre-headless (9~b114-0ubuntu1 Ubuntu:16.04/xenial [amd64])
Inst libatk-wrapper-java (0.33.3-6 Ubuntu:16.04/xenial [all])
Inst libatk-wrapper-java-jni (0.33.3-6 Ubuntu:16.04/xenial [amd64])
Inst openjdk-9-jre (9~b114-0ubuntu1 Ubuntu:16.04/xenial [amd64])
Inst jedit (5.3.0+dfsg-1 Ubuntu:16.04/xenial [all])
Conf java-wrappers (0.1.28 Ubuntu:16.04/xenial [all])
Conf java-common (0.56ubuntu2 Ubuntu:16.04/xenial [all])
Conf ca-certificates-java (20160321ubuntu1 Ubuntu:16.04/xenial-updates [all])
Conf openjdk-9-jre-headless (9~b114-0ubuntu1 Ubuntu:16.04/xenial [amd64])
Conf libatk-wrapper-java (0.33.3-6 Ubuntu:16.04/xenial [all])
Conf libatk-wrapper-java-jni (0.33.3-6 Ubuntu:16.04/xenial [amd64])
Conf openjdk-9-jre (9~b114-0ubuntu1 Ubuntu:16.04/xenial [amd64])
Conf jedit (5.3.0+dfsg-1 Ubuntu:16.04/xenial [all])

如果我使用两个单独的命令sudo apt-get install按照这个顺序安装jeditopenjdk-9-jre,那么我将会得到OpenJDK 8和OpenJDK 9的软件包。

或许值得一提的是元包:这是一个情况,其中一个包等于多个包。 - Sergiy Kolodyazhnyy

如果长列表中的任何一个软件包都无法安装,那么命令的执行将停止,并打印出一条有信息的错误消息。在终端中批量安装长列表的软件包也可能会令人沮丧,因为其中一些软件包需要与用户进行交互以成功安装。如果您在用户输入中犯了错误,那么您将不得不从头开始重新安装整个过程。
要想成功执行命令直到最后是困难的,除非您将初始的长列表分成每组25-40个软件包,并使用apt逐组安装这些软件包。这并不需要太多额外的时间,而且使得安装所有软件包更容易管理。
只需记住一件事。当运行sudo apt install时,它会锁定管理目录(/var/lib/dpkg/),所以在apt完全处理完成之前,请不要运行任何其他需要root权限的进程。例如,如果您正在终端中使用apt安装软件包,请不要尝试在新的选项卡或窗口中使用终端安装其他snap软件包,直到apt处理完成。