创建bash完成脚本以等号后自动完成路径?


11

我想创建一个bash完成脚本,该脚本可以识别形式为--arg和的参数--some-arg=file

在阅读了本教程和中的一些示例之后/usr/share/bash_completion/completions/,我编写了以下脚本(以节省使用Chromium键入一些标志的时间):

_chromium() 
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    # Some interesting options
    opts="
--disable-web-security
--easy-off-store-extension-install
--incognito
--load-extension=
--pack-extension=
--pack-extension-key=
--user-data-dir=
"
    # Handle --xxxxxx=file
    if [[ ${cur} == "--"*"=" ]] ; then
        # Removed failures (is my logic OK?)
        return 0
    fi

    # Handle other options
    if [[ ${cur} == -* ]] ; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
        return 0
    fi
}
complete -F _chromium chromium

我将其保存到~/bash_completions/chromium,并使用创建了一个符号链接sudo ln -s ~/bash_completions/chromium /usr/share/bash_completion/completions/chromium
然后,我使用加载了它. /usr/share/bash_completions/completions/chromium

现在,我遇到两个问题:

  • chromium --u<TAB>扩展到chromium --user-data-dir=<SPACE>(我不需要空格)。
  • 路径(目录和文件)不再完整。

我该如何解决这些问题?


切换到zsh是一种选择吗?
吉尔斯(Gilles)“所以,别再邪恶了”

Answers:


11

我找到了两个问题的解决方案!

  1. 要不附加空格,请使用nospace选项。这可以通过两种方式完成:

    • 将其传递给complete
      complete -o nospace -F _chromium chromium
    • 使用compopt内置的:(
      compopt -o nospace启用该选项)
      compopt +o nospace(禁用该选项)

    我在gnu.org的Bash文档8.7可编程完成内置函数中找到了它。

  2. 文件完成。
    • 彼得建议-f标志与compgen。我遵循了该建议,并将其实现为COMPREPLY=( $(compgen -f "$cur") )。在我尝试完成包含空格的路径之前,此方法运行良好。
      在Stack Overflow上,我找到了这个答案,建议手动创建完成列表(不使用compgen)。这种方法效果很好。
    • 使用该filenames选项告诉Readline compspec生成文件名,因此它可以:
      • 执行任何特定于文件名的处理(例如,在目录名称中添加斜杠,引用特殊字符或禁止尾随空格)
      • 使用不同的颜色指示文件类型(colored-stats启用)

借助于Bash的字符串操作(扩展~和处理空格),我构建了一个bash完成脚本,该脚本满足问题中所述的所有条件。

_chromium() 
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    # Some interesting options
    opts="
--disable-web-security
--easy-off-store-extension-install
--incognito
--load-extension=
--pack-extension=
--pack-extension-key=
--user-data-dir=
"
    # Handle --xxxxxx=
    if [[ ${prev} == "--"* && ${cur} == "=" ]] ; then
        compopt -o filenames
        COMPREPLY=(*)
        return 0
    fi
    # Handle --xxxxx=path
    if [[ ${prev} == '=' ]] ; then
        # Unescape space
        cur=${cur//\\ / }
        # Expand tilder to $HOME
        [[ ${cur} == "~/"* ]] && cur=${cur/\~/$HOME}
        # Show completion if path exist (and escape spaces)
        compopt -o filenames
        local files=("${cur}"*)
        [[ -e ${files[0]} ]] && COMPREPLY=( "${files[@]// /\ }" )
        return 0
    fi

    # Handle other options
    COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
    if [[ ${#COMPREPLY[@]} == 1 && ${COMPREPLY[0]} != "--"*"=" ]] ; then
        # If there's only one option, without =, then allow a space
        compopt +o nospace
    fi
    return 0
}
complete -o nospace -F _chromium chromium

很棒的答案,非常感谢。您节省了我很多时间。我使用-fswitch来完成文件路径,但是/如果它是目录,它就不会完成char。尽管这是一件小事。
Jiri Kremser 2014年

1

要完成文件名,请尝试传递-fcompgen

恐怕您无法在选项后消除空格,因为这是完成的工作方式-一旦找到唯一的匹配项,它将完全完成它。


感谢您的建议-f。我尝试了它,但是它不能正确处理空格:该路径/tmp/foo bar导致两个完成条目/tmp/foobar。关于垃圾邮件--arg=<SPACE>:我找到了解决方法,并将其发布在下面的答案中
罗伯W
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.