我很好奇某个软件包为我的系统提供了哪些命令。我所说的命令是指我可以从命令行运行的路径内可执行文件(ls
、grep
、sed
等)。
我是不是尝试从命令中找出包,可以使用以下命令:
dpkg -S `which command`
我想要相反的东西,一个来自包的命令列表。
答案1
下面的小循环将处理这个问题已安装软件包。
$ for f in $(dpkg -L login); do [[ $(type -P "${f##*/}") == "$f" ]] && echo ${f##*/}; done
nologin
lastlog
newgrp
faillog
su
login
sg
怎么运行的:
dpkg -L package
生成一个列表全部我们迭代的包中的文件。- 我们用一点 bashism 去掉目录名称:
${f##*/}
然后 - 使用 bash-builtin
type -P command
我们查看该命令是否在路径中以及其路径是否等于我们开始的文件。 - 我们通过发出缩短的命令来结束。
[[ condition ]] && command
只是 bash 中 if..then 语句的简写。
需要注意的是,并非所有软件包都包含您期望的命令。Apache 分为多个软件包(包括-common
和-bin
子软件包),并且vlc
命令不在vlc
软件包中,而是在中vlc-nox
。有许多诸如此类的例子。
这可以调整为Gilles 的想法,进行字符串匹配而不是实际检查,但将其全部保存在一个 bash 进程中(并且仍然使用所有的小路)。
for f in $(dpkg -L login); do [[ $f =~ ^${PATH//:/|} ]] && echo ${f##*/}; done
这里的主要区别是[[$f =~ ^${PATH//:/|} ]]
。这是 Bash 中的正则表达式搜索。该${PATH//:/|}
部分正在获取 $PATH 的内容并将其破解为一个肮脏的小正则表达式。条件应该检查字符串是否以路径的一部分开头。
答案2
列出软件包中位于 PATH 目录中的文件。您只需考虑默认 PATH,而不必考虑任何用户自定义,因为软件包仅使用标准目录。
dpkg -L PACKAGE-NAME… | sed -n 's!^\(/s\?bin\|/usr/s\?bin\|/usr/games\)/!!p' | sort
s\?
如果只想要供普通用户使用的程序,请删除这些部分sudo
。
如果未安装该软件包,请替换dpkg -L
为apt-file -F list
。
这遗漏了一些程序,因为它们是通过备择方案。例如,对于ftp
软件包中只提供了netkit-ftp
和,但这个软件包实际上提供了命令,因为是指向 的符号链接, 是指向系统上实现之一的符号链接,可能是。以下命令(这不是一个好的编程示例,只是一个大的单行命令)列出了软件包通过替代机制提供的命令,如当前配置的那样。pftp
ftp
/usr/bin/ftp
/etc/alternatives/ftp
ftp
/usr/bin/netkit-ftp
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…
如果您想要列出可以通过当前配置为指向不同包的替代方案提供的命令,则需要解析中的文件/var/lib/dpkg/alternatives
。
实现替代机制的符号链接和配置文件未在包中注册,而是在中自动注册postinst
,这使得查询已卸载包提供的替代方案变得困难(事实上,如果包的安装脚本不遵循约定,从技术上讲是不可能的)。
答案3
我的另一个答案相当确定,但只适用于已安装的软件包。这是一个破解版本,适用于尚未安装的软件包(但仅在主存储库中可用的软件包)
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
它非常复杂,因此我将写一个分解版本:
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
答案4
一种更简单的方法就是查询网络:
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 数据库。