Distinction between apt-cache and dpkg -l

apt is for managing remote repositories, dpkg - for locally installed packages. They're related. apt is front end to dpkg. When you run apt-get install package it gets .deb file, and installs it via dpkg. So numbers differ because there's a lot of packages available, but only fraction is installed locally on your system.

apt-cache can show both installed and non-installed packages, because it queries the apt cache - listing of what is available in remote repositories ( that cache is what you get when you do apt-get update). For instance,

$ apt-cache policy terminator
terminator:
  Installed: (none)
  Candidate: 1.91-1


$ dpkg -l terminator
dpkg-query: no packages found matching terminator

Note that there is another tool which can query list of installed/removed local packages, and that's dpkg-query. For instance,

$ dpkg-query -l 'libc6'
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
+++-====================-===============-===============-=============================================
ii  libc6:amd64          2.27-3          amd64           GNU C Library: Shared libraries
ii  libc6:i386           2.27-3          i386            GNU C Library: Shared libraries

$ dpkg -l libc6
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
+++-====================-===============-===============-=============================================
ii  libc6:amd64          2.27-3          amd64           GNU C Library: Shared libraries
ii  libc6:i386           2.27-3          i386            GNU C Library: Shared libraries

As per dpkg manual

dpkg can also be used as a front-end to dpkg-deb(1) and dpkg-query(1). The list of supported actions can be found later on in the ACTIONS section. If any such action is encountered dpkg just runs dpkg-deb or dpkg-query with the parameters given to it, but no specific options are currently passed to them, to use any such option the back-ends need to be called directly.

As far as dpkg-query goes, it should be noted that this tool is focused on querying the database of installed packages, and can output information in particular format(-f option plus -W action). For instance,

$ dpkg-query -W -f='PACK:${Package}\nARCH:${Architecture}\nSTAT:${Status}\n---\n' libc6
PACK:libc6
ARCH:amd64
STAT:install ok installed
---
PACK:libc6
ARCH:i386
STAT:install ok installed
---

Interestingly enough, dpkg database maintains listing of packages that are selected for removal or were removed at some point. dpkg-query can also take glob pattern as an argument, and depending on presence of absence of it show only installed/configured packages or all packages.


dpkg -l shows your installed package versions (starting with ii), removed ones (rc), and some others (e.g. installed but not configured, see the manpage).

apt-cache pkgnames shows you all the available package names (but not versions of the same package) in the added repositories.