59

At our university we can get almost any ubuntu package installed we want, but we are not superusers ourselves (we need to request packages being installed).

With some libraries it is not always easy to know whether the package is already installed or not. Is there a simple way/command to check this?

Radu Rădeanu
  • 169,590
Peter Smit
  • 7,587

9 Answers9

59
apt-cache policy <package name>
Oli
  • 293,335
18

I always just use this from the command line:

dpkg -l | grep mysql

so the above asks dpkg to list all the installed packages and then I grep for only those that have mysql in the name.

Rick
  • 3,647
  • 3
    dpkg -l "*mysql*" also works and does not hide the explanatory lines in the output. – Philipp Wendler Aug 09 '12 at 15:37
  • dpkg -l "*mysql*" (or dpkg -l '*mysql*') also makes special formatting of the output to fit each package on one line of the terminal window (grep doesn't). And this form allows you to choose the wildcard format (prefixes or suffixes), and whether to use wildcards at all (compared to grep). But grep gives nice coloring.. )) – vstepaniuk Feb 22 '18 at 16:07
  • This is not correct. dpkg -l does not ask dpkg to list all installed packages. The output of dpkg -l will also include packages that you installed but then removed. The correct way to do this is by either checking that the first column of the dpkg -l output is equal to ii or by running: dpkg-query --showformat '${Status}\n' --show $pkg which will show install ok installed for packages that are actually installed. – josch Feb 15 '22 at 12:40
7

One more variant, using aptitude this time:

aptitude show <package>

Tab completion works here as well.

6

You can use dselect. It provides non-su read-only access.

Also, dpkg -s <package name> provides a lot of details related to a package. Eg"

userme:~$ dpkg-query -s sl
Package: sl
Status: unknown ok not-installed
Priority: optional
Section: games
Pablo Bianchi
  • 15,657
Abhinav
  • 241
  • 1
    This is also available as just dpkg -s . And conversely, dpkg-query -l works just as well as dpkg -l or dpkg --list – belacqua Feb 09 '11 at 08:35
5

You may use dpkg-query -s <package> 2>/dev/null | grep -q ^"Status: install ok installed"$ in scripts, since it returns exit code 1, if the <package> is not installed, and 0 if the <package> is installed.

jarno
  • 5,600
  • 5
    Be careful: If dpkg -s returns 0, it doesn't necessarily mean that the package is fully/correctly installed. dpkg -s also returns 0 if the package is in half-configured or in config-files state (and I guess also in half-installed, but I didn't check that). See [the man page of dpkg(http://manpages.ubuntu.com/manpages/oneiric/man1/dpkg.1.html) for further "incomplete" states. – Ignitor Jan 17 '14 at 15:13
  • 1
    @Ignitor, good point. My answer was wrong. The package could even be removed, but not purged. So I think you have to examine the output to check, if the package is installed or not. – jarno Feb 06 '14 at 21:48
  • 2
    I edited the answer. Now it relies on output of dpkg-query. I don't know how portable this solution is; for example, may the text be displayed in another language in some system? – jarno Feb 06 '14 at 22:09
4

dpkg-query --showformat='${db:Status-Status}'

This produces a small output string which is unlikely to change and is easy to compare deterministically without grep:

pkg=hello
status="$(dpkg-query -W --showformat='${db:Status-Status}' "$pkg" 2>&1)"
if [ ! $? = 0 ] || [ ! "$status" = installed ]; then
  sudo apt install $pkg
fi

The $? = 0 check is needed because if you've never installed a package before, and after you remove certain packages such as hello, dpkg-query exits with status 1 and outputs to stderr:

dpkg-query: no packages found matching hello

instead of outputting not-installed. The 2>&1 captures that error message too when it comes preventing it from going to the terminal.

For multiple packages:

pkgs='hello certbot'
install=false
for pkg in $pkgs; do
  status="$(dpkg-query -W --showformat='${db:Status-Status}' "$pkg" 2>&1)"
  if [ ! $? = 0 ] || [ ! "$status" = installed ]; then
    install=true
    break
  fi
done
if "$install"; then
  sudo apt install $pkgs
fi

The possible statuses are documented in man dpkg-query as:

   n = Not-installed
   c = Config-files
   H = Half-installed
   U = Unpacked
   F = Half-configured
   W = Triggers-awaiting
   t = Triggers-pending
   i = Installed

The single letter versions are obtainable with db:Status-Abbrev, but they come together with the action and error status, so you get 3 characters and would need to cut it.

So I think it is reliable enough to rely on the uncapitalized statuses (Config-files vs config-files) not changing instead.

dpkg -s exit status

This unfortunately doesn't do what most users want:

pkgs='qemu-user pandoc'
if ! dpkg -s $pkgs >/dev/null 2>&1; then
  sudo apt-get install $pkgs
fi

because for some packages, e.g. certbot, doing:

sudo apt install certbot
sudo apt remove certbot

leaves certbot in state config-files, which means that config files were left in the machine. And in that state, dpkg -s still returns 0, because the package metadata is still kept around so that those config files can be handled more nicely.

To actually make dpkg -s return 1 as desired, --purge would be needed:

sudo apt remove --purge certbot

which actually moves it into not-installed/dpkg-query: no packages found matching.

Note that only certain packages leave config files behind. A simpler package like hello goes directly from installed to not-installed without --purge.

Tested on Ubuntu 20.10.

Python apt package

There is a pre-installed Python 3 package called apt in Ubuntu 18.04 which exposes an Python apt interface!

A script that checks if a package is installed and installs it if not can be seen at: https://stackoverflow.com/questions/17537390/how-to-install-a-package-using-the-python-apt-api/17538002#17538002

Here is a copy for reference:

#!/usr/bin/env python
# aptinstall.py

import apt import sys

pkg_name = "libjs-yui-doc"

cache = apt.cache.Cache() cache.update() cache.open()

pkg = cache[pkg_name] if pkg.is_installed: print "{pkg_name} already installed".format(pkg_name=pkg_name) else: pkg.mark_install()

try:
    cache.commit()
except Exception, arg:
    print &gt;&gt; sys.stderr, &quot;Sorry, package installation failed [{err}]&quot;.format(err=str(arg))

Check if an executable is in PATH instead

See: https://stackoverflow.com/questions/592620/how-can-i-check-if-a-program-exists-from-a-bash-script/22589429#22589429

See also

  • 1
    No. dpkg -s also exits with zero if the package is Status: deinstall ok config-files. To try this out yourself, run dpkg -l on your system and pass a package to dpkg -s which has an rc in the first column of your dpkg -l output. Even though the package is not installed, dpkg -s will exit with success. – josch Feb 15 '21 at 09:49
  • @josch I have discussed possibly related issues further at: https://stackoverflow.com/questions/1298066/check-if-an-apt-get-package-is-installed-and-then-install-it-if-its-not-on-linu/54239534#54239534 BTW. I don't have a perfect solution for it yet. – Ciro Santilli OurBigBook.com Feb 15 '21 at 09:55
  • Why are the solutions that use dpkg-query -W --showformat='${Status}\n' ... not perfect in your opinion? – josch Feb 15 '21 at 13:25
  • @josch have they clearly documented that the exact string output is a stable API? Just cautious since install ok installed is a bit long to grep for. I haven't really extensively researched this though. – Ciro Santilli OurBigBook.com Feb 15 '21 at 13:28
  • But true, dpkg-query -W --showformat='${db:Status-Status}' does seem decent, outputs only installed – Ciro Santilli OurBigBook.com Feb 15 '21 at 13:37
  • ${Status} gives you the plain value of the Status field from /var/lib/dpkg/status. If you have dpkg 1.17.11 or later, then yes ${db:Status-Status} gives you just what you want without the "eflag" or the "want". About stability: this didn't change since 1995. Is that stable enough for you? Proof: https://git.hadrons.org/cgit/debian/dpkg/dpkg.git/tree/lib/parsehelp.c?id=1b80fb16c22db72457d7a456ffbf1f70a8dfc0a5#n77 As for the documentation: just do man dpkg and look into the section INFORMATION ABOUT PACKAGES all field values like installed are documented there. – josch Feb 16 '21 at 17:34
  • @josch thanks for that link, yes, those strings seem to be quite embedded everywhere, should be fine to rely on them – Ciro Santilli OurBigBook.com Feb 16 '21 at 17:47
2

Simpler solution:

There is now an apt list command that lists installed packages. You can also search for a specific package with

apt list <package>

See man apt for more information.

0

You need to check the status printed by dpkg -l, example :

$ dpkg -l firefox-esr vim winff
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
+++-====================================-=======================-=======================-=============================================================================
hi  firefox-esr                          52.9.0esr+build2-0ubunt amd64                   Safe and easy web browser from Mozilla
ii  vim                                  2:8.1.1198-0york0~14.04 amd64                   Vi IMproved - enhanced vi editor
rc  winff                                1.5.3-3                 all                     graphical video and audio batch converter using ffmpeg or avconv

Here both vim and firefox-esr are installed, therefore you can type :

$ dpkg -l firefox-esr | grep -q ^.i && echo This package is installed. || echo This package is NOT installed.
This package is installed.
$ dpkg -l vim | grep -q ^.i && echo This package is installed. || echo This package is NOT installed.
This package is installed.
$ dpkg -l winff | grep -q ^.i && echo This package is installed. || echo This package is NOT installed.
This package is NOT installed.
SebMa
  • 2,291
-1

Example to use specific value as var in shell scripts (eg test.sh)

#!/bin/sh
PACKAGE="${1}"
INSTALLED=$(dpkg -l | grep ${PACKAGE} >/dev/null && echo "yes" || echo "no")

echo "${PACKAGE} is installed ... ${INSTALLED}"

Make it executable and go start with:

test.sh openssh-server

Or do whatever you want with in your scripts

wjandrea
  • 14,236
  • 4
  • 48
  • 98
  • This is incorrect. dpkg -l will also list packages that you once installed but then removed. Also, grepping dpkg -l output as you did will also match on all the text in the package descriptions. The right way is to use dpkg-query -W --showformat='${db:Status-Status}' $package. – josch Feb 15 '22 at 12:43