dpkg
Install and inspect Debian packages directly
dpkg is the program that installs Debian packages. It unpacks a .deb, runs its
maintainer scripts, records which files it owns, and remembers what state each package is in.
Everything apt does ends in a dpkg run.
The difference explains most of what is frustrating about dpkg used alone: dpkg knows
about packages, and apt knows about repositories. dpkg works with one file you already
have. It cannot download anything, does not know what a repository is, and, the important one,
will not resolve dependencies. It
checks them, refuses to configure a package whose dependencies are missing, and tells you what
was missing. Finding and installing those is apt's job.
That single fact is behind the most common dpkg experience: dpkg -i something.deb fails with
a wall of dependency problems, and the fix is to let apt clean up after it.
What dpkg is better at
Given that, most installing is better done through apt. What dpkg is for:
- Asking what is installed, and in what state.
dpkg -l,dpkg -sanddpkg -Lanswer from the local database with no network involved at all, which also makes them the tools that still work on a machine whose networking or apt configuration is broken. Listing what is installed is the tour of that question. - Finding which package owns a file.
dpkg -S /pathis the fastest way to identify an unfamiliar file on a system, and it only sees files that are already there. Which package provides a file covers the case where the file is still in the archive. - Inspecting a
.debbefore installing it.dpkg -Ianddpkg -cread a package file without touching the system, which is exactly what you want for a.debdownloaded from somewhere you are not sure about. - Repairing.
dpkg --configure -afinishes work an interrupted install left half-done, and is often the entire fix after a machine lost power mid-upgrade or an install was killed.
Reading package states
dpkg -l puts a two-letter state code in its first column, and it is the part people skip:
ii: installed and configured. The normal state.rc: removed, but its configuration files are still on disk. This is whatapt removeleaves behind, and why a package you "removed" can still be affecting things.apt purgeclears it, and remove vs purge vs autoremove is when to pick which.iUoriF: unpacked or half-configured. Something went wrong;dpkg --configure -ais the usual repair.un: not installed, but known about, usually because something else references it.
The first letter is what you wanted, the second is what is true. When they disagree, the package needs attention.
Installing a .deb, and why you probably shouldn't
dpkg -i file.deb installs a package file directly. If its dependencies are already present it
works; if they are not, it unpacks the package, fails to configure it, and leaves it in a broken
state you then have to repair.
For that reason, prefer:
sudo apt install ./file.deb
The ./ is what makes apt treat it as a file rather than a package name. apt unpacks it through
dpkg exactly as dpkg -i would, but resolves and downloads the dependencies first, so the
install either completes or does not start. Use dpkg -i when apt is not available or not
working, which happens, and is the reason to know the command exists.
Installing a .deb by hand walks the whole sequence, including
what the broken state looks like and how to read the package before you run either command.
dpkg -l is for reading, not parsing
dpkg -l is for reading, not parsing: its output is a fixed-width table that truncates the
description to the terminal width, and its exact columns are not a stable interface. When a
script needs a fact about a package, use dpkg-query -W -f and name the fields you want, or
test dpkg -s by exit status. Both are shown in the examples below.
Package operations need root. Every query on this page does not, and it is worth running them unprivileged out of habit.
Asking what is installed
All of these read the local package database. No network, no sudo, and they keep working on a machine whose apt configuration is broken.
Check whether a package is installed
dpkg -l cowsay
The first column is the state - ii is installed and configured. The table truncates its description column to the terminal width, so treat it as something to read rather than to parse.
Show output
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 cowsay 3.03+dfsg2-8 all configurable talking cow
Tell an installed package from a removed one
dpkg -l cowsay bash-completion | tail -3
rc means removed but not purged: the programs are gone and the configuration files are still on disk. This is the state that explains a package still affecting a system after you removed it.
Show output
+++-===============-============-============-==========================================
rc bash-completion 1:2.16.0-7 all programmable completion for the bash shell
ii cowsay 3.03+dfsg2-8 all configurable talking cow
Read everything dpkg knows about a package
dpkg -s cowsay
The full database entry - state, version, dependencies and description. Unlike dpkg -l this is a stable field-per-line format, and it needs no terminal width to be readable.
Show output
Package: cowsay
Status: install ok installed
Priority: optional
Section: games
Installed-Size: 92
Maintainer: James McDonald <james@jamesmcdonald.com>
Architecture: all
Version: 3.03+dfsg2-8
Depends: libtext-charwidth-perl, perl:any
Suggests: filters, cowsay-off
Description: configurable talking cow
Cowsay (or cowthink) will turn text into happy ASCII cows, with
speech (or thought) balloons. If you don't like cows, ASCII art is
available to replace it with some other creatures (Tux, the BSD
daemon, dragons, and a plethora of animals, from a turkey to
an elephant in a snake).
Homepage: https://web.archive.org/web/20120527202447/http://www.nog.net/~tony/warez/cowsay.shtml
Check installation state in a script
dpkg -s cowsay >/dev/null 2>&1 && echo installed || echo missing
Exit status rather than parsed output, so a formatting change can't break it. See Exit codes and error handling.
Show output
installed
List the files a package installed
dpkg -L cowsay | head -6
Every path the package put on disk, directories included. The complete answer to "where did that command come from, and what else came with it".
Show output
/.
/usr
/usr/games
/usr/games/cowsay
/usr/share
/usr/share/cowsay
Find which package owns a file
dpkg -S /usr/games/cowsay
The reverse lookup, and the fastest way to identify an unfamiliar file. It only knows about installed packages - for a file you don't have yet, apt-file search is the equivalent.
Show output
cowsay: /usr/games/cowsay
Find which package owns a command
dpkg -S "$(command -v gzip)"
command -v resolves the name on your PATH first, so this works without knowing where the binary lives.
Show output
gzip: /usr/bin/gzip
List a package's configuration files
dpkg -s bash-completion | grep -A3 ^Conffiles
Conffiles are the files dpkg treats as yours to edit - it will not overwrite a changed one on upgrade without asking. Shown here for a package in the rc state, whose programs are gone while every one of these files is still on disk.
Show output
Conffiles:
/etc/bash_completion a81b3f1cb197219b815942f4fc7fa94e
/etc/bash_completion.d/000_bash_completion_compat.bash 3834d4b9bcbc9a8bdb847f1a6727ae7a
/etc/profile.d/bash_completion.sh 3593c6b58d5ede41aedc83dff04c35f7
Inspecting a .deb before installing it
These read a package file and change nothing, which makes them the right first move for a .deb downloaded from somewhere you are not certain about.
Read a package file's metadata
dpkg -I cowsay-off.deb | head -12
Version, dependencies, maintainer and size, straight out of the file. No installation and no root required.
Show output
new Debian package, version 2.0.
size 8392 bytes: control archive=1024 bytes.
871 bytes, 21 lines control
500 bytes, 7 lines md5sums
Package: cowsay-off
Source: cowsay
Version: 3.03+dfsg2-8
Architecture: all
Maintainer: James McDonald <james@jamesmcdonald.com>
Installed-Size: 23
Depends: cowsay (>= 3.03+dfsg2-3)
Breaks: cowsay (<< 3.03+dfsg2-3)
List what a package file would install
dpkg -c cowsay-off.deb 2>/dev/null | head -6
Every path in the archive with its mode and owner, before anything is unpacked. The check to run when a third-party .deb might write somewhere it shouldn't.
Show output
drwxr-xr-x root/root 0 2020-05-11 06:43 ./
drwxr-xr-x root/root 0 2020-05-11 06:43 ./usr/
drwxr-xr-x root/root 0 2020-05-11 06:43 ./usr/share/
drwxr-xr-x root/root 0 2020-05-11 06:43 ./usr/share/cowsay/
drwxr-xr-x root/root 0 2020-05-11 06:43 ./usr/share/cowsay/cows/
-rw-r--r-- root/root 584 1999-08-14 07:17 ./usr/share/cowsay/cows/beavis.zen.cow
Extract a package's files without installing it
dpkg -x cowsay-off.deb /tmp/unpacked && find /tmp/unpacked -type f | sort | head -3
Unpacks the file tree into a directory of your choosing. No maintainer scripts run, nothing is registered and nothing is configured - useful for pulling one file out of a package. find reports in directory order, so sort is what makes the listing the same twice.
Show output
/tmp/unpacked/usr/share/cowsay/cows/beavis.zen.cow
/tmp/unpacked/usr/share/cowsay/cows/bong.cow
/tmp/unpacked/usr/share/cowsay/cows/mutilated.cow
Extract a package's control information
dpkg -e cowsay-off.deb /tmp/control && ls /tmp/control
Unpacks the maintainer scripts rather than the file tree. This is how to read what a package would run as root before letting it.
Show output
control
md5sums
Installing and removing directly
All of these need root, and none of them resolve dependencies. Their output is a live unpack - progress lines, sizes and your machine's architecture - so it isn't reproduced here. Prefer sudo apt install ./file.deb, which does the same unpacking with the dependencies sorted out first.
Install a package file
sudo dpkg -i cowsay-off.deb
Unpacks and configures a single .deb. Succeeds only if every dependency is already present; otherwise it leaves the package unpacked but unconfigured.
Fix the dependencies dpkg just complained about
sudo apt install -f
The standard follow-up to a failed dpkg -i. apt finds and installs the missing dependencies, then configures the package dpkg left half-done.
Install a .deb the way you actually should
sudo apt install ./cowsay-off.deb
The ./ makes apt treat the argument as a file rather than a package name. Same unpacking, but dependencies are resolved first, so the install either completes or never starts.
Remove a package, keeping its configuration
sudo dpkg -r cowsay-off
Takes a package name, not a file name - a common slip immediately after installing from a file. Leaves the package in the rc state.
Remove a package and its configuration
sudo dpkg -P cowsay-off
-P is purge: the programs and the configuration files both go.
Repairing a broken install
What to run when an install was interrupted by a killed session, a machine that lost power mid-upgrade, or a full disk.
Finish configuring everything left half-done
sudo dpkg --configure -a
Configures every package that was unpacked but never configured. Often the entire fix after an interrupted upgrade, and safe to run at any time - on a healthy system it prints nothing and does nothing.
Report packages that are installed but broken
sudo dpkg --audit
Lists packages in a state that needs attention, with a sentence saying why. Prints nothing when the system is healthy, which is the answer you want.
Check what state every package is in
dpkg -l | awk '$1 != "ii" && NR > 5 {print $1, $2}'
Anything whose state isn't ii - removed-but-not-purged packages and genuinely broken ones both show up here.
Show output
rc bash-completion
Reading the database in scripts
dpkg -l is a table for people. When a script needs a fact, name the field you want and nothing else can shift underneath you.
Print exactly one field
dpkg-query -W -f='${Version}\n' cowsay
-f takes a template of the fields you want. Nothing else is printed, so no header, column or description change can affect the result.
Show output
3.03+dfsg2-8
Print several fields in your own format
dpkg-query -W -f='${Package} ${Version} ${Status}\n' cowsay ca-certificates
Any field from the database, in any layout. ${Status} is the three words behind the two-letter code dpkg -l abbreviates.
Show output
ca-certificates 20250419 install ok installed
cowsay 3.03+dfsg2-8 install ok installed
Test whether a package is installed, properly
dpkg-query -W -f='${Status}' cowsay 2>/dev/null | grep -q "^install ok installed" && echo yes || echo no
More precise than dpkg -s, which succeeds for a package in the rc state too. This asks specifically whether the package is currently installed.
Show output
yes
List every package marked as held
dpkg --get-selections | grep hold || echo "nothing held"
dpkg records holds alongside apt's, so this and apt-mark showhold answer the same question from either side.
Show output
nothing held