繁体   English   中英

如何为路径上的所有可执行文件编写bash完成脚本?

[英]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. 

为了处理非可执行文件,我的第一个想法是过滤whichtype -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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM