How do I list commands a package provides? [duplicate]

The following little loop will handle this with installed packages.

$ for f in $(dpkg -L login); do [[ $(type -P "${f##*/}") == "$f" ]] && echo ${f##*/}; done
nologin
lastlog
newgrp
faillog
su
login
sg

How it works:

  • dpkg -L package generates a list of all the files in a package which we iterate through.
  • We strip off the directory name with a little bashism: ${f##*/} and
  • Using the bash-builtin type -P command we see if that command is both in the path and that its path equals the file we started with.
  • We finish by pumping out the shortened command.
  • [[ condition ]] && command is just a bash shorthand for an if..then statement.

It's important to note that not all packages contain the commands you would expect them to. Apache is split out over multiple packages (with -common and -bin subpackages) and the vlc command isn't in the vlc package, it's in vlc-nox. There are many examples like that.


This can be adapted per Gilles's idea, doing a string match instead of actually checking, but keeping it all in one bash process (and still using the whole path).

for f in $(dpkg -L login); do [[ $f =~ ^${PATH//:/|} ]] && echo ${f##*/}; done

The major difference here is the [[$f =~ ^${PATH//:/|} ]]. That's an in-Bash regex search. The ${PATH//:/|} part is taking the contents of $PATH and is hacking them into a dirty little regex. The condition should check the string begins with part of the path.


List the files in the package which are in a directory in the PATH. You only have to consider the default PATH, not any user customizations, since packages only use standard directories.

dpkg -L PACKAGE-NAME… | sed -n 's!^\(/s\?bin\|/usr/s\?bin\|/usr/games\)/!!p' | sort

Remove the s\? parts if you only want the programs intended for ordinary users without sudo.

If the package isn't installed, replace dpkg -L by apt-file -F list.

This misses a few programs because they are provided via alternatives. For example, for the ftp package, only netkit-ftp and pftp are provided, but this package actually provides the ftp command, because /usr/bin/ftp is a symbolic link to /etc/alternatives/ftp which is a symbolic link to one of the ftp implementations on the system, potentially /usr/bin/netkit-ftp. The following command (which isn't an example of good programming, just a big one-liner) lists the commands provided by a package via the alternatives mechanism, as currently configured.

perl -lwe 'foreach (`dpkg -L @ARGV`) {chomp; ++$p{$_}} foreach (</bin/* /sbin/* /usr/bin/* /usr/sbin/*>) {$e = readlink; next unless defined $e and $e =~ m!^/etc/alternatives/!; $t = readlink $e; print if $p{$t}}' PACKAGE_NAME…

If you want to list the commands that could be provided via an alternative which is currently configured to point to a different package, you need to parse the files in /var/lib/dpkg/alternatives.

Symbolic links and configuration files that implement the alternatives mechanisms are not registered in packages but registered automatically in postinst, which makes it difficult (and in fact technically impossible if a package's installation script doesn't follow conventions) to query the alternatives provided by an uninstalled package.


My other answer is fairly certain but only works for installed packages. Here's a crack at a version that works for packages not yet installed (but ones that are only available in the main repositories)

export PACKAGE="login"; source /etc/lsb-release; source <(dpkg-architecture); for f in $(wget -qO- "http://packages.ubuntu.com/$DISTRIB_CODENAME/$DEB_BUILD_ARCH/$PACKAGE/filelist" | sed -n '1,/<pre>/d;/<\/pre>/,$d;p'); do [[ $f =~ ^${PATH//:/|} ]] && echo ${f##*/}; done

It's horrifically more complicated so I'll write a broken down version:

export PACKAGE="login";
source /etc/lsb-release;
source <(dpkg-architecture);

URL="http://packages.ubuntu.com/$DISTRIB_CODENAME/$DEB_BUILD_ARCH/$PACKAGE/filelist"

# We grab the packages.ubuntu.com version of the file list (and strip it with sed)
for f in $(wget -qO- "$URL" | sed -n '1,/<pre>/d;/<\/pre>/,$d;p'); do

    # We then compare every file provided in the package with every path stub
    [[ $f =~ ^${PATH//:/|} ]] && echo ${f##*/};
done