bash 脚本可以包含自己的自动完成吗?

bep*_*ter 5 bash autocomplete compgen

有许多可用资源(123)解释了如何利用 bash 自动完成命令和参数的能力,但所有这些资源都需要向用户添加代码,~/.bash_profile或者/etc/bash_completion.d/*有没有办法使一个脚本及其可用的完成是独立的?作为一个粗略和不完整的例子:

~/bin/script-with-integrated-autocomplete.sh

#!/usr/bin/env bash

function _completions {
  complete ...
}

if [ "$1" == "completions" ]; then
  _completions
  exit 0
fi

# (Whatever the script really does goes here.)
# ...
# ...
Run Code Online (Sandbox Code Playgroud)

交易破坏者(在这个问题的上下文中)是上面的例子仍然需要你添加类似的东西~/bin/script-with-integrated-autocomplete.sh completions.profile完成。

有没有办法让单个 bash 脚本(文件)声明自己的完成并让 bash在调用时识别它们(理想情况下没有额外的系统或环境设置)?

fra*_*san 5

正如对您的问题的评论中所述,如果没有任何先前的配置并且不更改当前环境,Bash 无法完成命令的命令行。Bash 不会查看文件,也不会尝试解释它们,除非您显式执行或获取它们。

\n\n

我对这个主题的理解是,这样的功能不太可能很快进入 Bash,因为兼容性和资源问题 \xe2\x80\x94 作为一个 shell,它应该可靠地运行在各种不同的系统上,多种用途,适应多种用户的喜好;并且只有一个人作为开发者和维护者1

\n\n

虽然 Bash 提供了实现自动完成的工具,但完成生成器似乎在设计上就被设计为外部设施。事实上,您所寻找的内容可以通过现有工具和少量工作轻松实现。

\n\n

给定示例脚本foo

\n\n
#!/bin/bash\n\n# Setting up completion for foo. Only if the script is sourced\nif [ "$0" != "$BASH_SOURCE" ]; then\n    _foo() {\n        local cur\n        COMPREPLY=()\n        cur="${COMP_WORDS[COMP_CWORD]}"\n        COMPREPLY=( $(compgen -W \'bar baz\' -- "$cur") )\n        return 0\n    }\n    complete -F "_foo" "foo"\n    return\nfi\n\n# The body of foo -- what it does when executed\necho foo "$*"\n# ...\n
Run Code Online (Sandbox Code Playgroud)\n\n

使用bash-completion,可以通过将符号链接添加到foo存储动态加载的用户完成的目录来启用自包含自动完成:

\n\n
ln -s /path/to/foo ~/.local/share/bash-completion/completions/\n
Run Code Online (Sandbox Code Playgroud)\n\n

确切的路径可能会有所不同,您可以参考 bash-completion\'s FAQ 了解如何在您的系统上检查其值。

\n\n

如果没有 bash-completion,一种方法可能是定义一个默认的完成函数,如果命令满足某些条件,则该函数将提供命令(对应的文件);在这里,我们使用关联数组作为白名单(以避免盲目获取系统上的每个命令)。必须将此代码添加到您的.bashrc(或等效文件,即每次启动交互式 shell 时在当前环境中获取的文件):

\n\n
_default_completion () {\n    # Do nothing when completion is invoked for an empty command\n    if [ "$1" = "" ]; then\n        return 1\n    fi\n    # Get the command path, exit with failure if it can\'t be found\n    cmd=$(type -p "$1") || return 1\n    if [ "${_compwhitelist["${cmd##*/}"]}" = y ]; then\n        # Source the file corresponding to the command; on success,\n        # return 124 to trigger a new autocompletion attempt\n        source "$cmd" && return 124\n    fi\n}\ncomplete -D -F _default_completion -o bashdefault -o default\n\n# The list of commands with embedded completion\ndeclare -A _compwhitelist\n_compwhitelist[foo]=y\n
Run Code Online (Sandbox Code Playgroud)\n\n

我知道,您要求一个不需要编辑配置文件的解决方案,但请注意,始终需要一定量的配置。其中很大一部分是由发行版/软件包维护者完成的,即使用户可能永远不会意识到这一点。

\n\n

1 参考:Chet Ramey 网站上的Bash 主页以及相关 Bash FAQ中的“A1” 。

\n