如何为文件搜索和自定义搜索配置 bash 自动完成?

How to configure bash autocomplete for file search and custom search?

我想要一个自动完成上传脚本的命令,该命令将远程 运行,但用户也可以选择本地脚本进行上传。这是一个小例子来说明我在 bash 完整逻辑中遇到的问题。

_test_complete()
{
    local cur prev opts uploaded_scripts
    uploaded_scripts='proc1.sh proc2.sh'
    
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    if [[ ${prev} == '-s' ]] ; then
        COMPREPLY=( $(compgen -W "${uploaded_scripts}" -- ${cur}) )
        return 0
    fi
}

complete -F _test_complete remote

该示例几乎可以工作,但它不再自动完成本地文件搜索。

$ remote -s proc<TAB><TAB>
proc1.sh  proc2.sh

$ remote -s proc1.sh ./<TAB><TAB>

当您执行通常的文件搜索 ./ 时没有任何反应,应该列出当前目录中的文件。关于如何启用两者的任何想法?


编辑:上面的例子有一个问题,你只能选择一个完整的文件。我破解了一个有效的解决方案,但如果有人有更好的解决方案,请发表评论。还有来自已接受答案的 -o default

_test_complete()
{
    local cur prev opts uploaded_scripts
    uploaded_scripts='proc1.sh proc2.sh'

    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    
    [[ $COMP_CWORD == '1' ]] && LAST_OPT=''
    [[ ${prev:0:1} == '-' ]] && LAST_OPT=${prev}
    
    if [[ ${LAST_OPT} == '-s' ]]; then
        COMPREPLY=( $(compgen -o default -W "${uploaded_scripts}" -- ${cur}) )
        return 0
    fi
}

complete -F _test_complete remote

您只需将本地目录中的所有文件也添加到 COMPREPLYcomplete -f -- abc 生成以 abc.

开头的文件列表

顺便说一句:除了 "${COMP_WORDS[COMP_CWORD]}"COMP_CWORD-1,您还可以使用 </code> 和 <code>,它们由 bash 提供给任何完成函数.
但在这里我完全放弃了 if,因为你似乎想在 -s 之后允许多个文件。由于您不建议 -s 本身,因此一直建议文件:

_test_complete() { 
  local cur="" prev="" uploaded_scripts='proc1.sh proc2.sh'
  COMPREPLY=( $(
    compgen -W "${uploaded_scripts}" -- "$cur"
    compgen -f -- "$cur"
  ) )
}

complete -F _test_complete remote

注意:COMPREPLY=( $(...) )写起来容易,但有一些缺陷。包含空格的文件将被拆分为多个建议,而 * 等特殊符号将展开并生成更多建议。为避免这种情况,请设置 IFS=$'\n'; set -o noglob 或使用 mapfile -t COMPREPLY < <(...).
完成此操作后,您可以使用 complete -o filenames -F ... 以便在插入时也正确引用那些有问题的建议。

您可以使用 complete-o default 选项 (通常我会同时使用 -o default-o bashdefault :

complete -o default -F _test_complete remote

根据man bash

  • bashdefault

    Perform the rest of the default bash completions if the compspec generates no matches.

  • default

    Use readline's default filename completion if the compspec generates no matches.