[英]How to write a bash completion script for all executables on path?
我已经为这个用例提出了我编写或修改过的几个不同的脚本。 基本上,我希望选项'-x'的bash完成以完成PATH上的可执行文件。 这是一个包含在一个问题中的两个问题。
到目前为止,我遇到了麻烦,因为bash不容易区分PATH上的别名,内置函数,函数等和可执行文件。 / usr / share / bash-completion / bash_completion中的_commands
包装器函数完成了以上所有操作,但我没有使用别名,内置函数,函数等,只想完成碰巧可执行的命令路径。
例如......如果我输入scriptname -x bas[TAB]
,它应该用base64,bash,basename,bashbug完成。
这就是我的完成脚本现在的样子:
_have pygsparkle && {
_pygsparkle(){
local cur prev
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
case $prev in
-x|--executable)
# _command
executables=$({ compgen -c; compgen -abkA function; } | sort | uniq -u)
COMPREPLY=( $( compgen -W "$executables" -- "$cur" ) )
return 0
;;
esac
if [[ $cur = -* ]]; then
COMPREPLY=( $( compgen -W '--executable -h --help -x' -- "$cur" ) )
fi
}
complete -F _pygsparkle pygsparkle
}
它似乎按预期工作但{ compgen -c; compgen -abkA function; } | sort | uniq -u
{ compgen -c; compgen -abkA function; } | sort | uniq -u
{ compgen -c; compgen -abkA function; } | sort | uniq -u
是一个非常脏的黑客。 在zsh中,您可以在运行print -rl -- ${(ko)commands}
PATH上获得可执行文件的排序列表。 所以看来我至少缺少60多名高管,可能是因为uniq -u
正在转储与别名或函数同名的高管。
有一个更好的方法吗? 获取PATH上所有可执行文件的更好命令,或者服务于相同目的的预先存在的完成函数?
更新:确定以下功能在1/6秒内执行,看起来是最好的选择。 除非有任何其他建议,我可能只是关闭这个问题。
_executables(){
while read -d $'\0' path; do
echo "${path##*/}"
done < <(echo -n "$PATH" | xargs -d: -n1 -I% -- find -L '%' -maxdepth 1 -mindepth 1 -type f -executable -print0 2>/dev/null) | sort -u
}
我有一个run-in-back脚本 。 为了获得它的自动完成,我使用bash的内置complete
:
> complete -c <script-name>
> <script-name> ech[TAB]
> <script-name> echo
来自文档 :
command Command names. May also be specified as -c.
为了处理非可执行文件,我的第一个想法是过滤which
或type -P
但这非常慢。 更好的方法是只检查未知数。 使用@ Six的解决方案或其他一些解决方案来查找compgen -c
项目,而不是compgen -abkA function
。 对于两个列表中的所有内容,请检查type -P
。 例如:
function _executables {
local exclude=$(compgen -abkA function | sort)
local executables=$(
comm -23 <(compgen -c) <(echo $exclude)
type -tP $( comm -12 <(compgen -c) <(echo $exclude) )
)
COMPREPLY=( $(compgen -W "$executables" -- ${COMP_WORDS[COMP_CWORD]}) )
}
complete -F _executables <script-name>
我已经尝试了几次,但介绍-F
complete
似乎是一种缓慢的做事方式。 更不用说现在必须处理可执行文件的绝对/相对路径完成,非常繁琐的完整目录但不添加空间位并正确处理路径中的空间。
看起来你正在寻找compgen -c
对于如何列出用户PATH上可用的所有可执行文件的问题,似乎没有一个简单的答案。 唉,我已经广泛搜索了一个答案。
compgen
最初看起来可能是正确的方向,但它缺少只显示可执行文件的选项
compgen -c
将显示所有命令(包括别名,内置函数,可执行文件,函数和关键字)
compgen -abkA function
将显示除可执行文件之外的所有命令
因此可以通过“区分”两者来推测可用的可执行文件的近似值,即{ compgen -c; compgen -abkA function; } | sort | uniq -u
{ compgen -c; compgen -abkA function; } | sort | uniq -u
{ compgen -c; compgen -abkA function; } | sort | uniq -u
,但这显然有一些问题。
注意:要确认compgen -c
不起作用,您所要做的就是扫描结果并识别许多不可执行的条目。 您也可以尝试diff -u <(compgen -A function -abck | sort -u) <(compgen -c | sort -u)
,看看命令是否相同(当然一旦删除了重复项)。
因此,最好的选择是扫描路径上的每个目录。
总之,以下是现代系统的最佳选择。 它具有与compgen -c
相当的快速运行时间(~0.05秒),适用于完成。
executables(){
echo -n "$PATH" | xargs -d: -I{} -r -- find -L {} -maxdepth 1 -mindepth 1 -type f -executable -printf '%P\n' 2>/dev/null | sort -u
}
如果您使用的是旧版本的find / xargs(即busybox或BSD)和/或使用不支持进程替换的mksh(Android的默认shell),您将需要以下内容。 不那么快(~3.5秒)。
executables(){
find ${PATH//:/ } -follow -maxdepth 1 -type f -exec test -x '{}' \; -print0 2>/dev/null \
| while read -d $'\0' path; do
echo "${path##*/}"
done \
| sort -u
}
如果您使用上述设置并且由于某种原因在PATH中有空格,那么这应该可行。
executables(){
echo "$PATH" \
| tr ':' '\n' \
| while IFS= read path; do
find "$path" -follow -maxdepth 1 -type f -exec test -x '{}' \; -print0 2>/dev/null
done \
| while read -d $'\0' path; do
echo "${path##*/}"
done \
| sort -u
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.