自定义命令的 Bash 自动完成子目录

自定义命令的 Bash 自动完成子目录

我已经尝试了几个小时来让它工作但感觉我还没有成功。

我正在尝试通过从 Mac OS X 终端制表符完成目录名称来缩短我们的工作流程。

我们有一个内部工具,我们称之为bob,它会自动在 git 子模块上运行命令。我想让它自动完成子目录名称。问题是,这些子目录位于静态位置。

   project directory
   ->public
     ->submodules
       ->a-module
       ->another-module
       ->other-module
       ->some-module

命令从顶级项目目录运行,如下所示:

bob start bugfix anothermodule

我希望能够让 Tab 自动完成功能发挥作用,而不是像我们现在所做的那样,必须完全输入“anothermodule”。我们每天都会多次使用这种工作流程,如果能节省几秒钟的时间,并避免输入错误,那就太好了。

最终目标是:

bob start bugfix an<tab>

将自动完成至

bob start bugfix anothermodule

我尝试过CDPATH但很快意识到这不是我想要的,因为这不遵循命令cd,只是我的自定义命令。

我已经bash_completion安装了,但总体来说我不太擅长使用 bash。不过还是提一下,万一它能成为解决方案的一部分!

答案1

这是Kamil 的精彩回答-module从每个子目录名称的部分中删除连字符。

bugfix)
    curdir=$(pwd)
    cd public/submodules/ 2>/dev/null && _filedir -d
    # Strip the hyphen from `-module` in each sub-directory name.
    for ((i=0; i<${#COMPREPLY[@]}; i++)); do
        COMPREPLY[$i]="${COMPREPLY[$i]/-module/module}"
    done
    cd "$curdir"
    ;;

这部分仍有改进的空间:你可能需要输入连字符,即输入a-Tab以完成 to ,而不是在andamodule之间进行选择amoduleanothermodule(连字符仍然被完成功能剥离)。

答案2

这是正确的,bash_completion这是一个解决方案。我可以告诉你我的 Ubuntu 中有什么。我希望 Mac 上的情况至少也类似。

/etc/bash_completion文件来源/usr/share/bash-completion/bash_completion

目录中/usr/share/bash-completion还有一个completions子目录。这是脚本的位置。让我们看一下eject脚本:

# bash completion for eject(1)                             -*- shell-script -*-

_eject()
{
    local cur prev words cword
    _init_completion || return

    case $prev in
        -h|--help|-V|--version|-c|--changerslot|-x|--cdspeed)
            return
            ;;
        -a|--auto|-i|--manualeject)
            COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
            return
            ;;
    esac

    if [[ $cur == -* ]]; then
        COMPREPLY=( $( compgen -W '$( _parse_help "$1" )' -- "$cur" ) )
        return
    elif [[ $prev == @(-d|--default) ]]; then
        return
    fi

    _cd_devices
    _dvd_devices
} &&
complete -F _eject eject

# ex: ts=4 sw=4 et filetype=sh

即使没有阅读文档,我们也可以对其进行一些逆向工程,并根据您的情况进行调整。对我们来说,上述代码中最重要的部分是它说在 之后-a--auto -i或者--manualeject可以有onoff。在您的例子中,bugfix您需要一个目录名称。

(或者不是。你有another-module目录,但你使用anothermodule参数。现在我假设这是一个打字错误。如果不是,安东尼的回答我认为它将为你指明正确的方向。)

我们可以以某种方式提取您想要的目录并替换'on off',但利用现有代码可能更好。在我输入之后cdbash会自动完成目录,即使有空格或特殊字符,它也能正常工作。所以让我们看看_cd()函数;它在/usr/share/bash-completion/bash_completion,我不会在这里粘贴它。接下来,这个函数的关键部分似乎是调用。就在定义_filedir -dwhere 之前,我们有:_filedir()

# This function performs file and directory completion. It's better than
# simply using 'compgen -f', because it honours spaces in filenames.

答对了。

于是我复制了eject该名称下的脚本bob并编辑为以下形式:

# bash completion for bob                             -*- shell-script -*-

_bob()
{
    local cur prev words cword curdir
    _init_completion || return

    case $prev in
        bob)
            COMPREPLY=( $( compgen -W 'start stop foo bar' -- "$cur" ) )
            return
            ;;
        start)
            COMPREPLY=( $( compgen -W 'bugfix' -- "$cur" ) )
            return
            ;;
        bugfix)
            curdir=$(pwd)
            cd public/submodules/ 2>/dev/null && _filedir -d
            cd "$curdir"    
            ;;
    esac

} &&
complete -F _bob bob

现有bash会话不会注意到此文件,您必须运行一个新的bash来测试它。

是的,这是快速而肮脏的巫术编程,对不起。

注意我们下降到public/submodules/并返回。通常我会使用子 shell:

export -f _filedir
( cd … && _filedir -d )

但这样看起来_filedir不行。

相关内容