The basic way is:
dpkg -l | awk '/^ii/ {print $2}'
which returns a list of all installed packages (that's what the ^ii is for).
This doesn't cover the version numbers, but you won't be able to install based on version number anyway since those might have changed in the package pool of the repos being used.
I'm unclear why you think you need the version numbers since you can only realistically install the version that is in apt once you've run apt-get update, and since both systems are Debian 11, they are going to have the same version numbers of packages in their pools, unless they are using 3rd party repos or something.
You can generate a list for each system, then install only the packages that do not appear on the target machine list.
When I do stuff like this with scripting, I make it much more robust, so I'd test if package is installed on target system based on the source system list, and only install if not there, but you have to do that in a loop, because if the package is for some reason not available in the repos of the target system, the whole thing would fail, unless you are doing them one by one.
The clear way is to generate both lists, create a small list of diffs, packages not on the target system, then loop through that small list and install them one by one. Looping takes care of the orphaned issue since that install will just fail, and it will go on to do the next one in the list.
Bash compare two lists find missing items
That has an example of how to compare lists with only Bash, but it's a little more complicated than what you'd want.
Stuff like this I think you are much better off using a full script to do the work, I'd do it in Perl personally, but it would be whatever you like to use for such things.
Creating orphans
Another issue is that this will one by one install the missing packages, which might include various dependencies, but it could also include orphaned packages, which you don't want.
Orphaned packages might be present if for instance the system has undergone more than one upgrade to next Debian stable, which can leave orphans behind that don't get removed.
The major downside with this approach is you actually don't want to install dependencies of packages since those may change or get new versions, then those would be left orphaned but would not get removed by apt autoremove since you had explicitly installed them so they are flagged as explicit install, not a dependency pulled in. This will hit lib packages more often, but it can also hit other things that pull in a variety of packages when you install them.
You can work around this with even more scripting, but it gets to be a complicated, so if the goal is to just match packages, just install them one by one until it's done. It does slightly mess up the install in terms of adding some clutter but it's the easy way to do it.
Be careful with recommends!
Note that it's very important to use --no-install-recommends when you do this because otherwise you end up with a real mess. I always configure my systems apt to never install recommends for this reason. Recommends can easily daisy chain into something really out of control, I've seen examples online where installing a single small CLI program when not using --no-install-recommends it tried to pull in several hundred megabytes of packages due to the daisy chain issue.
In for example /etc/apt/apt.conf.d/ there are files, say 80basics, where you can add these lines:
APT::Install-Recommends "0";
APT::Install-Suggests "0";
APT::AutoRemove::SuggestsImportant "false";
APT::AutoRemove::RecommendsImportant "false";
I've never seen any case where I want recommends or suggests automatically installed.
Probably a better way to do this
I'm guessing that there is a better way to do this, because this is such a standard problem with syncing systems, maybe some native Debian tool, or some 3rd party tool, does this, I would be surprised if such a thing doesn't exist, though I don't know of one.
The second case is comparing two Debian 11 systems. For some reason one has python 2.7 installed and second doesn't and I am not sure what's missing. I used the latest netinst 11.5 iso image to build it but there is no python 2.7 in it.
– Cruise5 Oct 14 '22 at 20:21