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