如何列出程序包提供的命令?

我很好奇某个软件包为我的系统提供了什么命令。 通过命令,我的意思是我可以从命令行( lsgrepsed等)运行的路径内可执行文件。

不是试图从命令中解决这个问题,可以通过以下方式完成:

 dpkg -S `which command` 

我想要相反的,一个包的命令列表。

以下小循环将使用已安装的包处理此问题。

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

这个怎么运作:

  • dpkg -L package生成我们迭代的包中所有文件的列表。
  • 我们用一点基础来剥离目录名: ${f##*/}
  • 使用bash-builtin type -P command我们看到该命令是否都在路径中,并且其路径是否等于我们开始使用的文件。
  • 我们通过抽出缩短的命令完成。
  • [[ condition ]] && command只是if..then语句的bash简写。

重要的是要注意并非所有包都包含您期望它们的命令。 Apache分为多个包(使用-common-common子包),而vlc命令不在vlc包中,而是在vlc-nox 。 有很多这样的例子。


这可以根据Gilles的想法进行调整,进行字符串匹配而不是实际检查,但将其全部保存在一个bash过程中(并且仍然使用整个路径)。

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

这里的主要区别是[[$f =~ ^${PATH//:/|} ]] 。 那是一个in-Bash正则表达式搜索。 ${PATH//:/|}部分正在获取$ PATH的内容并将它们变成一个脏的小正则表达式。 条件应检查字符串是否以路径的一部分开头。

列出程序包中PATH目录中的文件。 您只需要考虑默认的PATH,而不是任何用户自定义,因为包只使用标准目录。

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

删除s\? 部分,如果你只想要没有sudo普通用户的程序。

如果未安装软件包,请使用apt-file -F list替换dpkg -L

这错过了一些程序,因为它们是通过替代方案提供的。 例如,对于ftp包,只提供了netkit-ftppftp ,但是这个包实际上提供了ftp命令,因为/usr/bin/ftp/etc/alternatives/ftp的符号链接,这是一个符号链接到系统上的一个ftp实现,可能是/usr/bin/netkit-ftp 。 以下命令(不是良好编程的示例,只是一个大的单行程序)列出了程序包通过替代机制提供的命令,如当前配置的那样。

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

如果要列出可以通过当前配置为指向其他程序包的替代方法提供的命令,则需要解析/var/lib/dpkg/alternatives

实现替代机制的符号链接和配置文件未在包中注册,而是在postinst自动注册,这使得查询卸载提供的替代方案变得困难(事实上,如果软件包的安装脚本不遵循惯例,在技术上是不可能的)包。

我的另一个答案是相当肯定的,但仅适用于已安装的软件包 这是一个适用于尚未安装的软件包的版本(但仅在主存储库中可用的版本)

 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,/
/d;/<\/pre>/,$d;p'); do [[ $f =~ ^${PATH//:/|} ]] && echo ${f##*/}; done

这是非常复杂的,所以我会写一个细分版本:

 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,/
/d;/<\/pre>/,$d;p'); do # We then compare every file provided in the package with every path stub [[ $f =~ ^${PATH//:/|} ]] && echo ${f##*/}; done

一种更简单的方法就是查询网页:

 release=$(lsb_release -sc) arch=$(uname -m) package=$@ for i in $package; do printf "List of files in $i package" curl http://packages.ubuntu.com/$release/$arch/$i/filelist 2>/dev/null | grep -oP '/[\w\d/.]+$ done 

这样做的好处是你只需要curl和sed(Ubuntu系统没有它们),你可以在必要的时候用wget轻松更改它。 它使用单个命令查询多个包,这是一个加号。


任何与其他编程语言+ html解析器的等价物应该更好地工作,如果包列表中的某些内容发生变化,则不太可能中断。

更改主机,您还可以查询Debian数据库。