Razzi's guide to apt

apt (advanced packaging tool) and its family of programs (apt-get, apt-cache, apt-file) are the default way to manage dependencies on Debian and derived distros (like Ubuntu).

apt keeps a local index of packages, which is what most commands reference.

To update this, run sudo apt update. If you don’t run that you may be dealing with stale package metadata.

Install a package

Use apt install

$ sudo apt install hello
Reading package lists... Done
Setting up hello (2.10-3) ...
Processing triggers for man-db (2.11.2-2) ...
Processing triggers for install-info (6.8-6+b1) ...
$ hello
Hello, world!

Note that since apt installs packages system-wide, you must have root permissions to install. If you don’t, you’ll get a permission error like follows:

$ apt install hello
E: Could not open lock file /var/lib/dpkg/lock-frontend - open (13: Permission denied)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), are you root?

List installed packages

Use apt list --installed

$ apt list --installed | head -5

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

aardvark-dns/stable,now 1.4.0-3 amd64 [installed,automatic]
accountsservice/stable,now 22.08.8-6 amd64 [installed,automatic]
acl/stable,now 2.3.1-3 amd64 [installed,automatic]
adduser/stable,now 3.134 all [installed]

Since I piped the output of this command, it is warning me that the output is subject to change. This is the case for all apt subcommands.

Rather than using apt directly in scripts, you should use its noninteractive versions, like so (this shows manually installed packages, not all packages):

guides $ apt-mark showmanual | head -5

Searching for packages

You can always use the web interface for this:


Search for packages by name

Use apt-cache search --names-only

$ apt-cache search --names-only openjdk
openjdk-17-dbg - Java runtime based on OpenJDK (debugging symbols)
openjdk-17-demo - Java runtime based on OpenJDK (demos and examples)

Search for packages by description

Use apt-cache search. This is the default behavior.

Show packages that include a file

Use apt-file search.

If you’re doing this for the first time, you’ll have to set up the apt file database.

$ sudo apt install apt-file
$ sudo apt-file update

Here’s how the search results look:

$ apt-file search zbarimg
zbar-tools: /usr/bin/zbarimg
zbar-tools: /usr/share/man/man1/zbarimg.1.gz

Show files provided by package

Use dpkg-query -L:

$ dpkg-query -L fish

Show info for package

Use apt show. The description field is a human-language description of the package.

$ apt show postgresql
Package: postgresql
Version: 15+248
Priority: optional
Section: database
Description: object-relational SQL database (supported version)

Show dependencies for package

Use apt depends

$ apt depends znc
  Depends: libboost-locale1.74.0 (>= 1.74.0+ds1)
  Depends: libc6 (>= 2.34)

Show which installed packages depends on a package (reverse dependencies)

Use apt rdepends --installed

$ apt rdepends --installed libldb2
Reverse Depends:
  Depends: samba-libs (>= 2:2.6.2)
  Depends: samba-libs (>= 2:2.6.2)

Download .deb for package

apt download

$ apt download znc
Get:1 https://deb.debian.org/debian bookworm/main amd64 znc amd64 1.8.2-3.1 [1846 kB]
Fetched 1846 kB in 0s (3857 kB/s)
$ ls

Download source code for package

Go to a directory you’d like to have the code in, then use apt source

$ apt source vim
Reading package lists... Done
NOTICE: 'vim' packaging is maintained in the 'Git' version control system at:
Please use:
git clone https://salsa.debian.org/vim-team/vim.git
to retrieve the latest (possibly unreleased) updates to the package.
dpkg-source: info: applying Fix-GH-267-where-indent-after-a-sub-would-not-work.patch
stuff $ ls
vim-9.0.1378/  vim_9.0.1378-2.debian.tar.xz  vim_9.0.1378-2.dsc  vim_9.0.1378.orig.tar.xz

In this example, vim is tracked in git (as are many packages) so there is a helpful hit about how to access the git source repository directly.

Install local .deb

Apt can operate on relative file paths like so:

$ sudo apt install ./rtx_2023.9.1_amd64.deb
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Note, selecting 'rtx' instead of './rtx_2023.9.1_amd64.deb'
The following NEW packages will be installed:
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/6955 kB of archives.
After this operation, 18.8 MB of additional disk space will be used.
Get:1 /home/razzi/hack/rtx_2023.9.1_amd64.deb rtx amd64 2023.9.1 [6955 kB]
Selecting previously unselected package rtx.

In this example, even though it says selecting rtx instead of ./rtx_2023.9.1_amd64.deb, note that when it fetches the package, the path is a file path, rather than a http url :)

A lot of times you’ll see this done with the underlying debian package manager, dkpg. To use that tool the command is sudo dpkg -i.

$ sudo dpkg -i znc_1.8.2-3.1_amd64.deb

Unpack a package

This one uses dpkg-deb for some reason. It takes the target directory as an argument, so I recommend creating a clean directory, moving the deb into it, and passing . as the directory:

unpack-ronin $ dpkg-deb -x ronin-0.1.0-1-any.deb .
unpack-ronin $ ls
ronin-0.1.0-1-any.deb  usr/

Uninstall a package

sudo apt remove. It will prompt you for whether or not to continue.

$ sudo apt remove docker

It might also tell you about packages that are installed but no longer required - they aren’t removed automatically. As the message says, use sudo apt autoremove to remove them.

Install build dependencies for package

apt build-dep

$ sudo apt build-dep vim

Install a package to the latest version

Usually this happens when you run sudo apt update && sudo apt upgrade -y.

But if you just want a single version upgraded to latest, sudo apt install it again.

$ sudo apt update
$ sudo apt install openjdk-17-jdk

Putting it all together: build & install vim at latest git commit

$ git clone https://salsa.debian.org/vim-team/vim.git
$ cd vim
$ sudo apt build-dep vim
$ ./configure --enable-python3interp --with-features=huge --enable-fail-if-missing
$ make
$ sudo make install