Home / Alt manpages / dpkg-query(1)

  • dpkg-query(1)
  • User command
  • linux

Inspect Installed Debian Packages with dpkg-query

You will use dpkg-query to answer five everyday package questions: is a package installed, what version is it, which files did it install, which package owns a path, and how can a script request stable fields? The commands below only read the dpkg database. They do not install, remove or reconfigure anything.

Allow about fifteen minutes. You need a Debian or Ubuntu system with dpkg-query installed and a normal shell. The examples were checked with dpkg-query 1.22.6 and package version 1.22.6ubuntu6.6 on this machine. Output from another dpkg release or distribution can differ in package versions, descriptions and local file lists.

1. Confirm the program and package version

Start with the version check. It is an ordinary, unprivileged command:

$ dpkg-query --version
Debian dpkg-query package management program query tool version 1.22.6 (amd64).

The version line is the version of the query tool, not the version of every package it can report. Keep this distinction when documenting a troubleshooting result.

Checkpoint: the command should exit successfully and print a version. If the shell says the command is missing, use the normal package-management process for your distribution to restore dpkg; do not copy a binary from an unrelated machine.

2. Check one package and its state

Use --show, or its short form -W, for a compact package and version result:

$ dpkg-query -W dpkg
dpkg	1.22.6ubuntu6.6

This command queries the local database. A line means that a matching database entry was found, not necessarily that the package is currently installed. Query the status field when that distinction matters:

$ dpkg-query -W -f='${binary:Package}\t${Version}\t${db:Status-Status}\n' dpkg
dpkg	1.22.6ubuntu6.6	installed

binary:Package can include an architecture qualifier where that is needed to make the package name unambiguous. The virtual db:Status-Status field extracts the status word from the package's database entry.

For the full record, use --status:

$ dpkg-query --status dpkg | sed -n '1,10p'
Package: dpkg
Essential: yes
Status: install ok installed
Priority: required
Section: admin

Do not parse the human-oriented output of -l in a script. It includes a heading and status columns designed for a terminal. Use --show with an explicit format instead.

3. List matching packages without losing wildcard characters

--list, or -l, is useful for a human inventory. With a pattern, quote the pattern so the shell does not expand it against filenames in the current directory:

$ dpkg-query -l 'dpkg*'
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/Half-configured/Half-installed/trig-aWait/Trig-pend
||/ Err?=(none)/Reinst-required
ii  dpkg       1.22.6ubuntu6.6  amd64  Debian package management system
ii  dpkg-dev   1.22.6ubuntu6.6  all    Debian package development tools

The three characters before a package name describe the desired action, package status and error flag. In the example, ii means install is desired, the package is installed, and no error flag is set. An uppercase status or error letter deserves investigation because it can indicate a serious package condition.

With no pattern, --list lists known entries except packages marked as purged. Patterns can also match real or virtual package names known through dependency fields.

4. Find who owns a file

Use --search, or -S, when you have a path and need to identify its package:

$ dpkg-query -S /usr/bin/dpkg-query
dpkg: /usr/bin/dpkg-query

The search accepts shell wildcard characters. A plain value that does not begin with *, ? or / is treated as a substring match, so an explicit absolute path is a good habit when you mean one pathname. The output can contain more than one package, followed by a colon and the matched path.

This database covers package-managed paths. It does not discover files created later by maintainer scripts, and it does not report alternatives. If the command finds nothing, check spelling, whether the path is generated at runtime, and whether a diversion is involved.

For scripts that parse file ownership, set a stable locale because diversion text is localised:

$ LC_ALL=C.UTF-8 LANGUAGE=C.UTF-8 dpkg-query -S /usr/bin/dpkg-query
dpkg: /usr/bin/dpkg-query

5. List a package's installed files

Use --listfiles, or -L, to list paths recorded for one package:

$ dpkg-query -L dpkg | sed -n '1,8p'
/.
/bin
/bin/dpkg
/etc
/etc/cron.daily
/etc/cron.daily/dpkg
/etc/dpkg
/etc/dpkg/dpkg.cfg

When you name more than one package, their file lists are separated by an empty line and remain in the order supplied. This is still a database query. It does not inspect the filesystem to prove that every listed path currently exists, and it does not include extra files created by maintainer scripts or alternatives.

6. Read package control files

For package control files installed under dpkg's administrative area, prefer --control-list and --control-show:

$ dpkg-query --control-list dpkg
postinst
postrm
md5sums
$ dpkg-query --control-show dpkg postinst | sed -n '1,6p'
#!/bin/sh
# See deb-postinst(5).

set -e

PROGNAME=dpkg

The first command gives the available control-file names. Pass one of those names to the second command. The older --control-path option can expose the internal path, but the manual marks it deprecated. Use it only for a narrowly understood recovery case, such as locating a damaging maintainer script that must be removed, and review the consequences before changing anything.

These commands print data to standard output. Redirecting that output to a file is safe if you choose a new destination, but do not edit a control file in place or run a maintainer script as a diagnostic. Changing dpkg's internal data can leave package operations inconsistent and may require elevated access.

7. Build a reliable script query

Use a format string with an explicit newline. The default --show format is package name, a tab and version; a custom format makes both the fields and separators visible in the script:

package='dpkg'
dpkg-query --show --showformat='${binary:Package}\t${Version}\t${db:Status-Status}\n' "$package"
status=$?
if [ "$status" -eq 0 ]; then
    printf '%s\n' 'package record found'
else
    printf 'dpkg-query failed with status %s\n' "$status" >&2
    exit "$status"
fi

Quote package patterns and variable expansions. A missing package or file can produce exit status 1, while invalid usage or a fatal database error produces status 2. For --control-path, --control-list and --control-show, the manual gives special fatal-error behaviour, so do not assume every query failure has the same meaning.

Do not add sudo to normal queries. Query operations should not require root. If a pager is invoked for a long result, the DPKG_PAGER or PAGER environment variable controls it; use --no-pager when a script or an audit log must not start an interactive pager.

Done means

  • You can distinguish the query tool version from a package's installed version and status.
  • You quote wildcard patterns passed to --list or --show.
  • You use formatted --show output for scripts instead of parsing the terminal table from --list.
  • You can identify a package owner and list package-managed files, with the limits of that database understood.
  • You use --control-list and --control-show before reaching for deprecated internal paths.
  • All checks remain read-only and unprivileged unless a separate recovery action has been explicitly reviewed.